array( 'label' => 'tagDiv', 'meta' => 'post_views_count', ), ); private static $rows = array(); private static $others = array(); private static $tables = array(); public static function register() { if ( ! class_exists( 'AIEO_Content_Vitals' ) && file_exists( AIEO_DIR . 'includes/class-aieo-content-vitals.php' ) ) { require_once AIEO_DIR . 'includes/class-aieo-content-vitals.php'; } if ( ! class_exists( 'AIEO_Product_Lifetime' ) && file_exists( AIEO_DIR . 'includes/class-aieo-product-lifetime.php' ) ) { require_once AIEO_DIR . 'includes/class-aieo-product-lifetime.php'; } add_filter( 'the_posts', array( __CLASS__, 'prime' ), 10, 2 ); add_filter( 'posts_clauses', array( __CLASS__, 'order_clauses' ), 10, 2 ); add_action( 'admin_init', static function () { foreach ( self::types() as $pt ) { add_filter( "manage_{$pt}_posts_columns", array( __CLASS__, 'add_column' ), 20 ); add_action( "manage_{$pt}_posts_custom_column", array( __CLASS__, 'render_column' ), 10, 2 ); add_filter( "manage_edit-{$pt}_sortable_columns", array( __CLASS__, 'sortable_column' ) ); } } ); } private static function types() { $types = class_exists( 'AIEO_Content_Vitals' ) && AIEO_Content_Vitals::enabled() ? AIEO_Content_Vitals::covered_types() : array(); if ( class_exists( 'AIEO_Product_Lifetime' ) && post_type_exists( 'product' ) ) { $types[] = 'product'; } return $types; } public static function add_column( $cols ) { foreach ( array_keys( self::COUNTERS ) as $key ) { if ( isset( $cols[ $key ] ) ) { unset( $cols[ $key ] ); self::$others[ $key ] = true; } } $cols[ self::COLUMN ] = '' . esc_html__( 'Engaged', 'ai-eshop-optimizer' ) . ''; return $cols; } public static function sortable_column( $cols ) { $cols[ self::COLUMN ] = array( self::COLUMN, true ); return $cols; } public static function prime( $posts, $query ) { if ( ! is_admin() || empty( $posts ) || ! is_object( $query ) || ! $query->is_main_query() ) { return $posts; } $types = self::types(); $ids = array( 'content' => array(), 'product' => array() ); foreach ( $posts as $p ) { if ( is_object( $p ) && isset( $p->ID ) && in_array( (string) $p->post_type, $types, true ) ) { $ids[ 'product' === $p->post_type ? 'product' : 'content' ][] = (int) $p->ID; } } self::load( $ids['content'], false ); self::load( $ids['product'], true ); return $posts; } public static function order_clauses( $clauses, $query ) { if ( ! is_admin() || ! is_object( $query ) || ! $query->is_main_query() || self::COLUMN !== $query->get( 'orderby' ) ) { return $clauses; } $type = (string) $query->get( 'post_type' ); if ( ! in_array( $type, self::types(), true ) || ! self::has_table( 'product' === $type ) ) { return $clauses; } global $wpdb; $order = 'ASC' === strtoupper( (string) $query->get( 'order' ) ) ? 'ASC' : 'DESC'; if ( 'product' === $type ) { $t = AIEO_Product_Lifetime::table(); $clauses['join'] .= " LEFT JOIN `{$t}` aieo_cv ON aieo_cv.product_id = {$wpdb->posts}.ID"; $views = 'aieo_cv.product_views'; } else { $t = $wpdb->prefix . AIEO_Content_Vitals::VITALS_TABLE; $clauses['join'] .= " LEFT JOIN `{$t}` aieo_cv ON aieo_cv.post_type = {$wpdb->posts}.post_type AND aieo_cv.content_id = {$wpdb->posts}.ID"; $views = 'aieo_cv.views_lifetime'; } $clauses['orderby'] = "COALESCE({$views}, 0) {$order}, {$wpdb->posts}.post_date DESC"; return $clauses; } public static function render_column( $col, $post_id ) { if ( self::COLUMN !== $col ) { return; } $post_id = (int) $post_id; self::load( array( $post_id ), 'product' === get_post_type( $post_id ) ); $row = self::$rows[ $post_id ] ?? null; $lines = array(); if ( null === $row ) { $lines[] = '' . esc_html__( 'No views counted yet', 'ai-eshop-optimizer' ) . ''; } else { $title = ''; if ( ! empty( $row['first_viewed_date'] ) && ! empty( $row['last_viewed_date'] ) ) { $format = (string) get_option( 'date_format' ); $title = ' title="' . esc_attr( sprintf( __( 'Counted from %1$s to %2$s.', 'ai-eshop-optimizer' ), mysql2date( $format, $row['first_viewed_date'] ), mysql2date( $format, $row['last_viewed_date'] ) ) ) . '"'; } $lines[] = '' . esc_html( number_format_i18n( (int) $row['views_lifetime'] ) ) . ''; $lines[] = esc_html( sprintf( __( '30 days: %s', 'ai-eshop-optimizer' ), number_format_i18n( (int) $row['views_30d'] ) ) ); } foreach ( array_keys( self::$others ) as $key ) { $lines[] = esc_html( sprintf( __( '%1$s: %2$s', 'ai-eshop-optimizer' ), self::COUNTERS[ $key ]['label'], number_format_i18n( (int) get_post_meta( $post_id, self::COUNTERS[ $key ]['meta'], true ) ) ) ); } echo implode( '
', $lines ); } private static function load( array $ids, $product ) { $ids = array_values( array_diff( array_filter( array_unique( array_map( 'intval', $ids ) ) ), array_keys( self::$rows ) ) ); if ( empty( $ids ) ) { return; } foreach ( $ids as $id ) { self::$rows[ $id ] = null; } if ( ! self::has_table( $product ) ) { return; } global $wpdb; $in = implode( ',', $ids ); if ( $product ) { $t = AIEO_Product_Lifetime::table(); $sql = "SELECT product_id AS content_id, product_views AS views_lifetime, product_views_30d AS views_30d, first_viewed_date, last_viewed_date FROM `{$t}` WHERE product_id IN ({$in})"; } else { $t = $wpdb->prefix . AIEO_Content_Vitals::VITALS_TABLE; $sql = "SELECT content_id, views_lifetime, views_30d, first_viewed_date, last_viewed_date FROM `{$t}` WHERE content_id IN ({$in})"; } $rows = $wpdb->get_results( $sql, ARRAY_A ); foreach ( (array) $rows as $r ) { self::$rows[ (int) $r['content_id'] ] = $r; } } private static function has_table( $product ) { global $wpdb; $t = $product ? AIEO_Product_Lifetime::table() : $wpdb->prefix . AIEO_Content_Vitals::VITALS_TABLE; if ( ! isset( self::$tables[ $t ] ) ) { self::$tables[ $t ] = (string) $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $t ) ) ) === $t; } return self::$tables[ $t ]; } }