> */ private array $all_abilities = array(); /** * Constructor. * * @since 0.2.0 */ public function __construct() { parent::__construct( array( 'singular' => 'ability', 'plural' => 'abilities', 'ajax' => false, ) ); } /** * {@inheritDoc} * * @return array Column definitions. */ public function get_columns(): array { return array( 'name' => __( 'Name', 'ai' ), 'slug' => __( 'Slug', 'ai' ), 'provider' => __( 'Provider', 'ai' ), 'actions' => __( 'Actions', 'ai' ), ); } /** * {@inheritDoc} * * @return array Sortable column definitions. */ public function get_sortable_columns(): array { return array( 'name' => array( 'name', false ), 'slug' => array( 'slug', false ), 'provider' => array( 'provider', false ), ); } /** * {@inheritDoc} */ public function prepare_items(): void { $columns = $this->get_columns(); $hidden = array(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array( $columns, $hidden, $sortable ); // Get abilities once and store the full list for filter option derivation. $abilities = Ability_Handler::get_all_abilities(); $this->all_abilities = $abilities; // Apply search filter. $search = isset( $_REQUEST['s'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( ! empty( $search ) ) { $abilities = array_filter( $abilities, static function ( $ability ) use ( $search ) { return stripos( $ability['name'], $search ) !== false || stripos( $ability['slug'], $search ) !== false || stripos( $ability['description'], $search ) !== false; } ); } // Apply provider filter. $provider_filter = isset( $_REQUEST['provider'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['provider'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( ! empty( $provider_filter ) && 'all' !== $provider_filter ) { // Known origins filter by origin, so abilities carrying a custom // provider label still appear under their Core/Plugin/Theme bucket // (consistent with the statistics); custom providers filter by // their exact label. $known_origins = array( 'Core', 'Plugin', 'Theme' ); $abilities = array_filter( $abilities, static function ( $ability ) use ( $provider_filter, $known_origins ) { if ( in_array( $provider_filter, $known_origins, true ) ) { return ( $ability['origin'] ?? '' ) === $provider_filter; } return $ability['provider'] === $provider_filter; } ); } // Apply category filter. $category_filter = isset( $_REQUEST['category'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['category'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( ! empty( $category_filter ) && 'all' !== $category_filter ) { $abilities = array_filter( $abilities, static function ( $ability ) use ( $category_filter ) { return ( $ability['category'] ?? '' ) === $category_filter; } ); } // Apply sorting. $orderby = isset( $_REQUEST['orderby'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ) : 'name'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $order = isset( $_REQUEST['order'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) : 'asc'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended usort( $abilities, static function ( $a, $b ) use ( $orderby, $order ) { $result = 0; if ( isset( $a[ $orderby ] ) && isset( $b[ $orderby ] ) ) { $result = strcasecmp( $a[ $orderby ], $b[ $orderby ] ); } return 'asc' === $order ? $result : -$result; } ); // Pagination. $per_page = 20; $current_page = $this->get_pagenum(); $total_items = count( $abilities ); $this->set_pagination_args( array( 'total_items' => $total_items, 'per_page' => $per_page, 'total_pages' => (int) ceil( $total_items / $per_page ), ) ); $this->items = array_slice( $abilities, ( $current_page - 1 ) * $per_page, $per_page ); } /** * Get sorted unique categories derived from the already-fetched ability list. * * @since 0.7.0 * * @return array */ public function get_unique_categories(): array { $categories = array(); foreach ( $this->all_abilities as $ability ) { if ( empty( $ability['category'] ) ) { continue; } $categories[] = $ability['category']; } $categories = array_unique( $categories ); sort( $categories ); return $categories; } /** * Gets sorted unique providers derived from the already-fetched ability list. * * Known origins (Core, Plugin, Theme) come first in their canonical order; * any custom providers (set via an ability's `meta['provider']`) follow * alphabetically. * * @since 1.3.0 * * @return list Known provider origins followed by custom providers sorted alphabetically. */ public function get_unique_providers(): array { $known = array( 'Core', 'Plugin', 'Theme' ); $custom = array(); foreach ( $this->all_abilities as $ability ) { if ( empty( $ability['provider'] ) || in_array( $ability['provider'], $known, true ) ) { continue; } $custom[] = $ability['provider']; } $custom = array_unique( $custom ); sort( $custom ); return array_merge( $known, $custom ); } /** * {@inheritDoc} * * @param array $item Item data. */ public function column_default( $item, $column_name ): string { return isset( $item[ $column_name ] ) ? esc_html( $item[ $column_name ] ) : '—'; } /** * {@inheritDoc} * * @param array $item Item data. */ public function column_name( $item ): string { $detail_url = add_query_arg( array( 'page' => 'ai-abilities-explorer', 'action' => 'view', 'ability' => $item['slug'], ), admin_url( 'tools.php' ) ); return sprintf( '%s', esc_url( $detail_url ), esc_html( $item['name'] ) ); } /** * {@inheritDoc} * * @param array $item Item data. */ public function column_slug( $item ): string { return sprintf( '%s', esc_html( $item['slug'] ) ); } /** * {@inheritDoc} * * @param array $item Item data. */ public function column_provider( $item ): string { $provider = $item['provider']; $class = 'ability-provider ability-provider-' . sanitize_title( $provider ); return sprintf( '%s', esc_attr( $class ), esc_html( Ability_Handler::get_provider_label( $provider ) ) ); } /** * {@inheritDoc} * * @param array $item Item data. */ public function column_actions( $item ): string { $detail_url = add_query_arg( array( 'page' => 'ai-abilities-explorer', 'action' => 'view', 'ability' => $item['slug'], ), admin_url( 'tools.php' ) ); $test_url = add_query_arg( array( 'page' => 'ai-abilities-explorer', 'action' => 'test', 'ability' => $item['slug'], ), admin_url( 'tools.php' ) ); return sprintf( '%s %s', esc_url( $detail_url ), esc_html__( 'View', 'ai' ), esc_url( $test_url ), esc_html__( 'Test', 'ai' ) ); } /** * {@inheritDoc} */ public function extra_tablenav( $which ): void { if ( 'top' !== $which ) { return; } $provider_filter = isset( $_REQUEST['provider'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['provider'] ) ) : 'all'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $category_filter = isset( $_REQUEST['category'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['category'] ) ) : 'all'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>