array( 'booking', 'abientot_manage_bookings' ), 'finance' => array( 'booking', 'abientot_manage_settings' ), 'privacy' => array( 'customer', 'abientot_manage_customers' ), 'customer_booking' => array( 'customer', 'abientot_manage_bookings' ) ); public static function register(): void { add_action( 'wp_ajax_abientot_record_choices', array( self::class, 'ajax' ) ); } private static function allowed( string $scope ): bool { return isset( self::SCOPES[ $scope ] ) && current_user_can( self::SCOPES[ $scope ][1] ); } private static function label( array $row, string $kind ): string { if ( $kind === 'customer' ) { return trim( (string) $row['display_name'] ) . ( ! empty( $row['email'] ) ? ' · ' . $row['email'] : '' ); } return $row['customer_name'] . ' · ' . $row['service_name'] . ' · ' . DateTimeHelper::format_utc_datetime( $row['start_utc'], $row['timezone'] ) . ' · ' . $row['staff_name'] . ' · ' . $row['status_label']; } public static function ajax(): void { check_ajax_referer( 'abientot_record_choices', 'nonce' ); $input = \Abientot\Support\Input::post( 'abientot_record_choices', 'nonce' ); $scope = $input->key( 'scope' ); if ( ! self::allowed( $scope ) ) { wp_send_json_error( array(), 403 ); } $query = $input->text( 'query' ); if ( strlen( $query ) > 760 ) { wp_send_json_error( array(), 400 ); } $page = max( 1, min( 1000000, $input->int( 'choice_page', 1 ) ) ); $kind = self::SCOPES[ $scope ][0]; $repository = $kind === 'booking' ? new AppointmentsRepository() : new CustomersRepository(); try { $rows = $repository->list_for_admin( array( 'search' => $query ), 26, ( $page - 1 ) * 25 ); $more = count( $rows ) > 25; $items = array(); foreach ( array_slice( $rows, 0, 25 ) as $row ) { $items[] = array( 'id' => (int) $row['id'], 'label' => self::label( $row, $kind ) ); } wp_send_json_success( array( 'items' => $items, 'more' => $more, 'page' => $page ) ); } catch ( \Throwable $e ) { wp_send_json_error( array(), 500 ); } } public static function summary( int $id, string $scope = 'booking' ): string { if ( ! self::allowed( $scope ) || $id < 1 ) { return '—'; } static $cache = array(); $key = get_current_user_id() . ':' . $scope . ':' . $id; if ( ! array_key_exists( $key, $cache ) ) { $cache[ $key ] = ( new AppointmentsRepository() )->find_for_admin( $id ); } $row = $cache[ $key ]; if ( ! $row ) { return esc_html__( 'Unavailable booking', 'abientot' ); } $label = esc_html( self::label( $row, 'booking' ) ); return current_user_can( 'abientot_manage_bookings' ) ? '' . $label . '' : $label; } public static function render( string $name, string $label, int $selected = 0, bool $required = true, string $scope = 'booking' ): void { if ( ! self::allowed( $scope ) ) { return; } $kind = self::SCOPES[ $scope ][0]; $repository = $kind === 'booking' ? new AppointmentsRepository() : new CustomersRepository(); $rows = $repository->list_for_admin( array(), 25 ); $chosen = $selected ? ( $kind === 'booking' ? $repository->find_for_admin( $selected ) : $repository->find( $selected ) ) : null; wp_enqueue_script( 'abientot-record-picker', plugins_url( 'assets/admin/record-picker.js', ABIENTOT_PLUGIN_FILE ), array(), (string) filemtime( ABIENTOT_PLUGIN_DIR . 'assets/admin/record-picker.js' ), true ); $id = wp_unique_id( 'abientot-choice-' ); ?>