__( 'Custom Code', 'admin-optimizer' ), 'plural' => __( 'Custom Codes', 'admin-optimizer' ), 'ajax' => false, ] ); } /** * Get columns. * * @return array */ public function get_columns(): array { return [ 'cb' => '', 'title' => __( 'Title', 'admin-optimizer' ), 'type' => __( 'Type', 'admin-optimizer' ), 'location' => __( 'Location', 'admin-optimizer' ), 'output' => __( 'Output', 'admin-optimizer' ), 'status' => __( 'Status', 'admin-optimizer' ), 'date' => __( 'Date', 'admin-optimizer' ), ]; } /** * Get sortable columns. * * @return array */ protected function get_sortable_columns(): array { return [ 'title' => [ 'title', false ], 'date' => [ 'date', true ], ]; } /** * Get post status views for the list table. * * @return array */ protected function get_views(): array { $statuses = $this->get_listable_post_statuses(); $counts = wp_count_posts( Custom_Code::POST_TYPE, 'readable' ); $current_status = $this->get_current_post_status(); $views = []; $total = 0; foreach ( $statuses as $status => $status_object ) { if ( 'trash' === $status ) { continue; } $total += isset( $counts->{$status} ) ? (int) $counts->{$status} : 0; } $views['all'] = $this->get_status_view_link( '', __( 'All', 'admin-optimizer' ), $total, '' === $current_status ); foreach ( $statuses as $status => $status_object ) { $count = isset( $counts->{$status} ) ? (int) $counts->{$status} : 0; if ( 0 === $count ) { continue; } $views[ $status ] = $this->get_status_view_link( $status, $status_object->label, $count, $status === $current_status ); } return $views; } /** * Get bulk actions. * * @return array */ protected function get_bulk_actions(): array { if ( 'trash' === $this->get_current_post_status() ) { return [ 'restore' => __( 'Restore', 'admin-optimizer' ), 'delete' => __( 'Delete Permanently', 'admin-optimizer' ), ]; } return [ 'activate' => __( 'Activate', 'admin-optimizer' ), 'deactivate' => __( 'Deactivate', 'admin-optimizer' ), 'trash' => __( 'Move to Trash', 'admin-optimizer' ), ]; } /** * Default column fallback. * * @param \WP_Post $item * @param string $column_name * @return string */ protected function column_default( $item, $column_name ): string { return ''; } /** * Checkbox column. * * @param \WP_Post $item * @return string */ protected function column_cb( $item ): string { return sprintf( '', absint( $item->ID ) ); } /** * Title column with row actions. * * @param \WP_Post $item * @return string */ protected function column_title( $item ): string { $edit_url = get_edit_post_link( $item->ID ); $trash_url = get_delete_post_link( $item->ID ); $toggle_url = wp_nonce_url( add_query_arg( [ 'action' => 'ao_cc_toggle_status', 'post' => absint( $item->ID ), ], admin_url( 'admin-post.php' ) ), 'ao_cc_toggle_status_' . absint( $item->ID ) ); $restore_url = wp_nonce_url( add_query_arg( [ 'action' => 'ao_cc_restore_code', 'post' => absint( $item->ID ), ], admin_url( 'admin-post.php' ) ), 'ao_cc_restore_code_' . absint( $item->ID ) ); $force_delete_url = wp_nonce_url( add_query_arg( [ 'action' => 'ao_cc_delete_code', 'post' => absint( $item->ID ), ], admin_url( 'admin-post.php' ) ), 'ao_cc_delete_code_' . absint( $item->ID ) ); $status = get_post_status( $item->ID ); $title = sprintf( '%s', esc_url( $edit_url ), esc_html( $item->post_title !== '' ? $item->post_title : __( '(no title)', 'admin-optimizer' ) ) ); if ( 'draft' === $status ) { $title .= ' — ' . esc_html__( 'Draft', 'admin-optimizer' ) . ''; } if ( 'trash' === $status ) { $actions = [ 'restore' => sprintf( '%s', esc_url( $restore_url ), esc_html__( 'Restore', 'admin-optimizer' ) ), 'delete' => sprintf( '%s', esc_url( $force_delete_url ), esc_js( __( 'Are you sure you want to permanently delete this item?', 'admin-optimizer' ) ), esc_html__( 'Delete Permanently', 'admin-optimizer' ) ), ]; } else { $is_published = 'publish' === $status; $toggle_label = $is_published ? __( 'Deactivate', 'admin-optimizer' ) : __( 'Activate', 'admin-optimizer' ); $actions = [ 'edit' => sprintf( '%s', esc_url( $edit_url ), esc_html__( 'Edit', 'admin-optimizer' ) ), 'toggle' => sprintf( '%s', esc_url( $toggle_url ), esc_html( $toggle_label ) ), 'trash' => sprintf( '%s', esc_url( $trash_url ), esc_js( __( 'Are you sure you want to trash this item?', 'admin-optimizer' ) ), esc_html__( 'Trash', 'admin-optimizer' ) ), ]; } return $title . $this->row_actions( $actions ); } /** * Type column. * * @param \WP_Post $item * @return string */ protected function column_type( $item ): string { $type = get_post_meta( $item->ID, '_ao_cc_type', true ); $labels = [ 'css' => 'CSS', 'js' => 'JavaScript', 'html' => 'HTML', ]; $labels = apply_filters( 'ao_cc_list_type_labels', $labels ); return esc_html( $labels[ $type ] ?? ucfirst( $type ) ); } /** * Location column. * * @param \WP_Post $item * @return string */ protected function column_location( $item ): string { $locations = get_post_meta( $item->ID, '_ao_cc_locations', true ); $post_ids = get_post_meta( $item->ID, '_ao_cc_post_ids', true ); $labels = []; if ( is_array( $locations ) && ! empty( $locations ) ) { foreach ( $locations as $key ) { $labels[] = Custom_Code::ALL_LOCATIONS[ $key ] ?? $key; } } if ( is_array( $post_ids ) && ! empty( $post_ids ) ) { $labels[] = sprintf( /* translators: %s: comma-separated list of post IDs */ __( 'Post IDs: %s', 'admin-optimizer' ), implode( ', ', array_map( 'absint', $post_ids ) ) ); } $output = $labels ? esc_html( implode( ', ', $labels ) ) : '—'; return apply_filters( 'ao_cc_list_location_output', $output, $item ); } /** * Output column — shows display method for CSS or position for JS/HTML. * * @param \WP_Post $item * @return string */ protected function column_output( $item ): string { $type = get_post_meta( $item->ID, '_ao_cc_type', true ); if ( 'css' === $type ) { $display_raw = get_post_meta( $item->ID, '_ao_cc_display', true ); $display = '' !== $display_raw ? $display_raw : 'inline'; return esc_html( ucfirst( $display ) ); } $position_labels = [ 'wp_head' => __( 'Head', 'admin-optimizer' ), 'wp_body_open' => __( 'Body open', 'admin-optimizer' ), 'wp_footer' => __( 'Footer', 'admin-optimizer' ), ]; $position = get_post_meta( $item->ID, '_ao_cc_position', true ); return isset( $position_labels[ $position ] ) ? esc_html( $position_labels[ $position ] ) : '—'; } /** * Post status column. * * @param \WP_Post $item * @return string */ protected function column_status( $item ): string { return 'publish' === $item->post_status ? esc_html__( 'Activated', 'admin-optimizer' ) : esc_html__( 'Deactivated', 'admin-optimizer' ); } /** * Date column. * * @param \WP_Post $item * @return string */ protected function column_date( $item ): string { return esc_html( get_the_date( get_option( 'date_format' ), $item ) ); } /** * Type filter dropdown rendered above the table. * * @param string $which * @return void */ public function extra_tablenav( $which ): void { if ( 'top' !== $which ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended $current_type = isset( $_REQUEST['ao_cc_type_filter'] ) ? sanitize_key( wp_unslash( $_REQUEST['ao_cc_type_filter'] ) ) : ''; ?>
0 ? $saved_per_page : 20; $current_page = $this->get_pagenum(); $post_status = $this->get_current_post_status(); $this->_column_headers = [ $this->get_columns(), [], $this->get_sortable_columns(), ]; $args = [ 'post_type' => Custom_Code::POST_TYPE, 'post_status' => $post_status ? $post_status : $this->get_default_query_post_statuses(), 'posts_per_page' => $per_page, 'paged' => $current_page, 'orderby' => 'date', 'order' => 'DESC', ]; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $orderby = isset( $_REQUEST['orderby'] ) ? sanitize_key( wp_unslash( $_REQUEST['orderby'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $order = isset( $_REQUEST['order'] ) && 'asc' === strtolower( sanitize_key( wp_unslash( $_REQUEST['order'] ) ) ) ? 'ASC' : 'DESC'; if ( in_array( $orderby, [ 'title', 'date' ], true ) ) { $args['orderby'] = $orderby; $args['order'] = $order; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended $search = isset( $_REQUEST['s'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) : ''; if ( ! empty( $search ) ) { $args['s'] = $search; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended $type_filter = isset( $_REQUEST['ao_cc_type_filter'] ) ? sanitize_key( wp_unslash( $_REQUEST['ao_cc_type_filter'] ) ) : ''; if ( in_array( $type_filter, Custom_Code::TYPES, true ) ) { $args['meta_query'] = [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query [ 'key' => '_ao_cc_type', 'value' => $type_filter, ], ]; } $query = new \WP_Query( $args ); $this->items = $query->posts; $this->set_pagination_args( [ 'total_items' => $query->found_posts, 'per_page' => $per_page, 'total_pages' => $query->max_num_pages, ] ); } /** * Get listable post status objects. * * @return array */ private function get_listable_post_statuses(): array { $statuses = get_post_stati( [], 'objects' ); $listable = []; foreach ( $statuses as $status => $status_object ) { if ( in_array( $status, [ 'auto-draft', 'inherit' ], true ) ) { continue; } if ( in_array( $status, [ 'publish', 'future', 'draft', 'pending', 'private', 'trash' ], true ) || ! empty( $status_object->show_in_admin_all_list ) || ! empty( $status_object->show_in_admin_status_list ) ) { $listable[ $status ] = $status_object; } } return $listable; } /** * Get the currently requested post status. * * @return string */ private function get_current_post_status(): string { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $post_status = isset( $_REQUEST['post_status'] ) ? sanitize_key( wp_unslash( $_REQUEST['post_status'] ) ) : ''; $statuses = $this->get_listable_post_statuses(); return isset( $statuses[ $post_status ] ) ? $post_status : ''; } /** * Get post statuses used by the default "All" view. * * @return array */ private function get_default_query_post_statuses(): array { $statuses = array_keys( $this->get_listable_post_statuses() ); return array_values( array_diff( $statuses, [ 'trash' ] ) ); } /** * Build a post status view link. * * @param string $status * @param string $label * @param int $count * @param bool $current * @return string */ private function get_status_view_link( string $status, string $label, int $count, bool $current ): string { $args = []; if ( '' !== $status ) { $args['post_status'] = $status; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( ! empty( $_REQUEST['s'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $args['s'] = sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ); } // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( ! empty( $_REQUEST['ao_cc_type_filter'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $args['ao_cc_type_filter'] = sanitize_key( wp_unslash( $_REQUEST['ao_cc_type_filter'] ) ); } $url = Custom_Code::get_module_admin_url( $args ); $class = $current ? ' class="current" aria-current="page"' : ''; return sprintf( '%3$s (%4$s)', esc_url( $url ), $class, esc_html( $label ), number_format_i18n( $count ) ); } }