__( 'popular_post', 'top-10' ), // Singular name of the listed records. 'plural' => __( 'popular_posts', 'top-10' ), // plural name of the listed records. ) ); $this->all_post_type = array( 'all' => __( 'All post types', 'top-10' ), ); $this->network_wide = $network_wide; } /** * Get the fixed IDs reserved for site-wide tracking contexts. * * The class only exists in the Pro build. Keeping this lookup optional lets * the shared statistics table continue to work in the free plugin. * * @return array Reserved context IDs. */ protected function get_sitewide_context_ids() { if ( ! class_exists( 'WebberZone\\Top_Ten\\Pro\\Sitewide_Database' ) || ! \WebberZone\Top_Ten\Pro\Sitewide_Database::is_available() ) { return array(); } return \WebberZone\Top_Ten\Pro\Sitewide_Database::get_context_ids(); } /** * Build a SQL condition matching any reserved site-wide context ID. * * @param string $alias Count-table alias. * @return string SQL condition, or an always-false condition when Pro is not loaded. */ protected function get_sitewide_context_condition( $alias = 'ttt' ) { $ids = $this->get_sitewide_context_ids(); if ( empty( $ids ) ) { return '0=1'; } return sprintf( '%s.postnumber IN (%s)', $alias, implode( ',', array_map( 'intval', $ids ) ) ); } /** * Get the site-wide context key for a result row. * * @param array $item Result row. * @return string Context key, or an empty string for a post row. */ protected function get_item_context_key( $item ) { if ( ! isset( $item['ID'] ) || ! class_exists( 'WebberZone\\Top_Ten\\Pro\\Sitewide_Database' ) || ! \WebberZone\Top_Ten\Pro\Sitewide_Database::is_available() ) { return ''; } return \WebberZone\Top_Ten\Pro\Sitewide_Database::get_context_key( $item['ID'], $item['blog_id'] ?? null ); } /** * Get a translated label for a site-wide context key. * * @param string $context_key Context key. * @return string Context label. */ protected function get_sitewide_context_label( $context_key ) { if ( '' === $context_key || ! class_exists( 'WebberZone\\Top_Ten\\Pro\\Sitewide_Database' ) || ! \WebberZone\Top_Ten\Pro\Sitewide_Database::is_available() ) { return ''; } return \WebberZone\Top_Ten\Pro\Sitewide_Database::get_context_label( $context_key ); } /** * Build the search condition for site-wide context labels and keys. * * @param string $search Search text. * @return string SQL condition, or an always-false condition when Pro is not loaded. */ protected function get_sitewide_context_search_condition( $search ) { if ( ! class_exists( 'WebberZone\\Top_Ten\\Pro\\Sitewide_Database' ) || ! \WebberZone\Top_Ten\Pro\Sitewide_Database::is_available() ) { return '0=1'; } global $wpdb; $like = '%' . $wpdb->esc_like( $search ) . '%'; $conditions = array(); foreach ( \WebberZone\Top_Ten\Pro\Sitewide_Database::CONTEXT_IDS as $context_key => $context_id ) { $searchable = $context_key . ' ' . $this->get_sitewide_context_label( $context_key ); $conditions[] = $wpdb->prepare( 'ttt.postnumber = %d AND %s LIKE %s', $context_id, $searchable, $like ); } return '(' . implode( ' OR ', $conditions ) . ')'; } /** * Resolve a safe ordering clause for statistics queries. * * @since 4.5.0 * * @param array $args Query arguments. * @return array{orderby:string,order:string} Ordering fields. */ protected function get_ordering( $args ) { $orderby = ''; if ( ! empty( $_REQUEST['orderby'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $orderby = sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } elseif ( ! empty( $args['orderby'] ) ) { $orderby = $args['orderby']; } if ( ! in_array( $orderby, array( 'title', 'daily_count', 'total_count' ), true ) ) { $orderby = 'total_count'; } $order = ''; if ( ! empty( $_REQUEST['order'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $order = sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } elseif ( ! empty( $args['order'] ) ) { $order = $args['order']; } if ( ! in_array( $order, array( 'asc', 'ASC', 'desc', 'DESC' ), true ) ) { $order = 'DESC'; } return array( 'orderby' => $orderby, 'order' => strtoupper( $order ), ); } /** * Fetch network-wide popular posts in two phases. * * The first query selects only the requested page in the sort order. The * second query fills in the other count using exact post/blog pairs, which * avoids joining and grouping the entire network's count tables. * * @since 4.5.0 * * @param int $per_page Posts per page. * @param int $page_number Page number. * @param array $args Query arguments. * @param string $from_date Inclusive lower date boundary. * @param string $to_date Exclusive upper date boundary. * @return array Array of popular posts. */ protected function get_network_popular_posts( $per_page, $page_number, $args, $from_date, $to_date ) { global $wpdb; $ordering = $this->get_ordering( $args ); $orderby = 'daily_count' === $ordering['orderby'] ? 'daily_count' : 'total_count'; $offset = max( 0, ( (int) $page_number - 1 ) * (int) $per_page ); $limit = max( 0, (int) $per_page ); if ( 0 === $limit ) { return array(); } $daily_table = $wpdb->base_prefix . 'top_ten_daily'; $total_table = $wpdb->base_prefix . 'top_ten'; // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared if ( 'daily_count' === $orderby ) { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $sql = $wpdb->prepare( "SELECT postnumber AS ID, blog_id, SUM(cntaccess) AS daily_count FROM {$daily_table} WHERE dp_date >= %s AND dp_date < %s GROUP BY postnumber, blog_id ORDER BY daily_count {$ordering['order']}, postnumber ASC, blog_id ASC LIMIT %d, %d", $from_date, $to_date, $offset, $limit ); } else { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $sql = $wpdb->prepare( "SELECT postnumber AS ID, blog_id, cntaccess AS total_count FROM {$total_table} ORDER BY cntaccess {$ordering['order']}, postnumber ASC, blog_id ASC LIMIT %d, %d", $offset, $limit ); } $results = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared if ( empty( $results ) ) { return array(); } $pair_conditions = array(); foreach ( $results as $result ) { $pair_conditions[] = $wpdb->prepare( '(postnumber = %d AND blog_id = %d)', $result['ID'], $result['blog_id'] ); } $pairs = implode( ' OR ', $pair_conditions ); if ( 'daily_count' === $orderby ) { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $other_results = $wpdb->get_results( "SELECT postnumber AS ID, blog_id, cntaccess AS total_count FROM {$total_table} WHERE {$pairs}", ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared } else { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $other_results = $wpdb->get_results( $wpdb->prepare( "SELECT postnumber AS ID, blog_id, SUM(cntaccess) AS daily_count FROM {$daily_table} WHERE dp_date >= %s AND dp_date < %s AND ({$pairs}) GROUP BY postnumber, blog_id", $from_date, $to_date ), ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared } $other_counts = array(); foreach ( $other_results as $result ) { $key = (int) $result['ID'] . ':' . (int) $result['blog_id']; $other_counts[ $key ] = $result[ 'daily_count' === $orderby ? 'total_count' : 'daily_count' ]; } foreach ( $results as &$result ) { $key = (int) $result['ID'] . ':' . (int) $result['blog_id']; if ( 'daily_count' === $orderby ) { $result['total_count'] = isset( $other_counts[ $key ] ) ? $other_counts[ $key ] : 0; } else { $result['daily_count'] = isset( $other_counts[ $key ] ) ? $other_counts[ $key ] : 0; } } unset( $result ); // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared return $results; } /** * Retrieve the Top 10 posts * * @param int $per_page Posts per page. * @param int $page_number Page number. * @param array $args Array of arguments. * * @return array Array of popular posts */ public function get_popular_posts( $per_page = 20, $page_number = 1, $args = null ) { global $wpdb; $args = is_array( $args ) ? $args : array(); // Initialise some variables. $fields = array(); $where = ''; $join = ''; $groupby = ''; $orderby = ''; $limits = ''; $sql = ''; $blog_id = get_current_blog_id(); $from_date = isset( $args['post-date-filter-from'] ) ? $args['post-date-filter-from'] : current_time( 'd M Y' ); $from_date = gmdate( 'Y-m-d', strtotime( $from_date ) ); $to_date = isset( $args['post-date-filter-to'] ) ? $args['post-date-filter-to'] : current_time( 'd M Y' ); $to_date = gmdate( 'Y-m-d', strtotime( $to_date ) ); $from_date = $from_date . ' 00:00:00'; $to_date = gmdate( 'Y-m-d 00:00:00', strtotime( $to_date . ' +1 day' ) ); if ( $this->network_wide ) { $result = $this->get_network_popular_posts( $per_page, $page_number, $args, $from_date, $to_date ); foreach ( $result as &$row ) { $row['context_key'] = $this->get_item_context_key( $row ); if ( '' !== $row['context_key'] ) { $row['title'] = $this->get_sitewide_context_label( $row['context_key'] ); $row['post_type'] = __( 'Site-wide', 'top-10' ); $row['post_date'] = ''; $row['post_author'] = 0; } } unset( $row ); return $result; } /* Start creating the SQL */ $table_name_daily = $wpdb->base_prefix . 'top_ten_daily'; $table_name = $wpdb->base_prefix . 'top_ten AS ttt'; $sitewide_sql = $this->get_sitewide_context_condition(); // Fields to return. $fields[] = "{$wpdb->posts}.post_title as title"; $fields[] = "{$wpdb->posts}.post_type"; $fields[] = "{$wpdb->posts}.post_date"; $fields[] = "{$wpdb->posts}.post_author"; $fields[] = 'ttt.postnumber as ID'; $fields[] = 'ttt.cntaccess as total_count'; $fields[] = 'SUM(ttd.daily_count) as daily_count'; $fields[] = 'ttt.blog_id as blog_id'; $fields = implode( ', ', $fields ); // Create the JOIN clause. $join .= " LEFT JOIN {$wpdb->posts} ON ttt.postnumber={$wpdb->posts}.ID "; $join .= $wpdb->prepare( " LEFT JOIN ( SELECT postnumber, blog_id, SUM(cntaccess) AS daily_count FROM {$table_name_daily} " . // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared 'WHERE dp_date >= %s AND dp_date < %s AND blog_id = %d GROUP BY postnumber, blog_id ) AS ttd ON ttt.postnumber=ttd.postnumber AND ttt.blog_id=ttd.blog_id ', $from_date, $to_date, $blog_id ); // Create the base WHERE clause. $where .= $wpdb->prepare( ' AND ttt.blog_id = %d ', $blog_id ); // Posts need to be from the current blog only. $where .= " AND (($wpdb->posts.post_status = 'publish' OR $wpdb->posts.post_status = 'inherit') OR {$sitewide_sql}) "; // Show published posts, attachments and site-wide contexts. // If search argument is set, do a search for it. if ( ! empty( $args['search'] ) ) { $post_search = $wpdb->prepare( "$wpdb->posts.post_title LIKE %s", '%' . $wpdb->esc_like( $args['search'] ) . '%' ); $context_search = $this->get_sitewide_context_search_condition( $args['search'] ); $where .= " AND ({$post_search} OR {$context_search}) "; } // If post filter argument is set, do a search for it. if ( isset( $args['post-type-filter'] ) && $this->all_post_type['all'] !== $args['post-type-filter'] ) { $where .= $wpdb->prepare( " AND $wpdb->posts.post_type = %s ", $args['post-type-filter'] ); } else { $post_types = get_post_types( array( 'public' => true, ) ); $where .= " AND ($wpdb->posts.post_type IN ('" . join( "', '", $post_types ) . "') OR {$sitewide_sql}) "; } $ordering = $this->get_ordering( $args ); $orderby = $ordering['orderby'] . ' ' . $ordering['order']; // Create the base LIMITS clause. $limits = $wpdb->prepare( ' LIMIT %d, %d ', ( $page_number - 1 ) * $per_page, $per_page ); $groupby = ' GROUP BY ttt.postnumber, ttt.blog_id '; $orderby = " ORDER BY {$orderby} "; $sql = "SELECT $fields FROM {$table_name} $join WHERE 1=1 $where $groupby $orderby $limits"; $result = $wpdb->get_results( $sql, 'ARRAY_A' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared foreach ( $result as &$row ) { $row['context_key'] = $this->get_item_context_key( $row ); if ( '' !== $row['context_key'] ) { $row['title'] = $this->get_sitewide_context_label( $row['context_key'] ); $row['post_type'] = __( 'Site-wide', 'top-10' ); $row['post_date'] = ''; $row['post_author'] = 0; } } unset( $row ); return $result; } /** * Returns the count of records in the database. * * @param array $args Array of arguments. * @return null|string null|string */ public function record_count( $args = null ) { global $wpdb; $args = is_array( $args ) ? $args : array(); if ( $this->network_wide ) { $cache_key = 'tptn_network_popular_posts_count'; $cached = get_site_transient( $cache_key ); if ( false !== $cached ) { return (string) (int) $cached; } $count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->base_prefix}top_ten" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared /** This filter is documented in includes/admin/class-dashboard-widgets.php */ $ttl = max( 0, (int) apply_filters( 'tptn_network_dashboard_cache_ttl', 15 * MINUTE_IN_SECONDS ) ); if ( $ttl > 0 ) { set_site_transient( $cache_key, $count, $ttl ); } return (string) $count; } $where = ''; $join = ''; $sql = "SELECT COUNT(*) FROM {$wpdb->base_prefix}top_ten as ttt"; $join = "LEFT JOIN {$wpdb->posts} ON ttt.postnumber={$wpdb->posts}.ID"; $sitewide_sql = $this->get_sitewide_context_condition(); $where .= $wpdb->prepare( ' AND ttt.blog_id = %d ', get_current_blog_id() ); $where .= " AND (($wpdb->posts.post_status = 'publish' OR $wpdb->posts.post_status = 'inherit') OR {$sitewide_sql}) "; if ( ! empty( $args['search'] ) ) { $post_search = $wpdb->prepare( "{$wpdb->posts}.post_title LIKE %s", '%' . $wpdb->esc_like( $args['search'] ) . '%' ); $context_search = $this->get_sitewide_context_search_condition( $args['search'] ); $where .= " AND ({$post_search} OR {$context_search}) "; } if ( isset( $args['post-type-filter'] ) && $this->all_post_type['all'] !== $args['post-type-filter'] ) { $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_type = %s ", $args['post-type-filter'] ); } else { $post_types = get_post_types( array( 'public' => true, ) ); $where .= " AND ($wpdb->posts.post_type IN ('" . join( "', '", $post_types ) . "') OR {$sitewide_sql}) "; } return $wpdb->get_var( "$sql $join WHERE 1=1 $where" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared } /** * Delete the post count for this post. * * @param int $id Post ID. * @param int $blog_id Blog ID. */ public static function delete_post_count( $id, $blog_id ) { \WebberZone\Top_Ten\Counter::delete_count( $id, $blog_id, false ); \WebberZone\Top_Ten\Counter::delete_count( $id, $blog_id, true ); } /** * Text displayed when no post data is available */ public function no_items() { esc_html_e( 'No popular posts available.', 'top-10' ); } /** * Render a column when no column specific method exist. * * @param array $item Current item. * @param string $column_name Column name. * * @return mixed */ public function column_default( $item, $column_name ) { switch ( $column_name ) { case 'daily_count': return \WebberZone\Top_Ten\Util\Helpers::number_format_i18n( absint( $item[ $column_name ] ) ); default: // Show the whole array for troubleshooting purposes. return ''; } } /** * Render the checkbox column. * * @param array $item Current item. * @return string */ public function column_cb( $item ) { return sprintf( '', 'bulk-delete', $item['ID'], $item['blog_id'] ); } /** * Render the title column. * * @param array $item Current item. * @return string */ public function column_title( $item ) { $context_key = $this->get_item_context_key( $item ); if ( '' !== $context_key ) { return sprintf( '%1$s (%2$s, id:%3$s)', esc_html( $this->get_sitewide_context_label( $context_key ) ), esc_html__( 'site-wide', 'top-10' ), esc_html( $item['ID'] ) ); } $delete_nonce = wp_create_nonce( 'tptn_delete_entry' ); $page = isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $post = $this->network_wide ? get_blog_post( $item['blog_id'], $item['ID'] ) : get_post( $item['ID'] ); if ( null === $post ) { return sprintf( '%s (id:%2$s)', __( 'Invalid post ID. This post might have been deleted.', 'top-10' ), $item['ID'] ); } $actions = array( 'view' => sprintf( '' . __( 'View', 'top-10' ) . '', get_permalink( $item['ID'] ) ), 'edit' => sprintf( '' . __( 'Edit', 'top-10' ) . '', get_edit_post_link( $item['ID'] ) ), 'delete' => sprintf( '' . __( 'Delete', 'top-10' ) . '', esc_attr( $page ), 'delete', absint( $item['ID'] ), absint( $item['blog_id'] ), $delete_nonce ), ); // Return the title contents. return sprintf( '%1$s (id:%2$s)%3$s', $post->post_title, $item['ID'], $this->network_wide ? '' : $this->row_actions( $actions ), is_multisite() ? get_blog_permalink( $item['blog_id'], $item['ID'] ) : get_permalink( $item['ID'] ) ); } /** * Handles the post date column output. * * @param array $item Current item. * @return string Post date. */ public function column_date( $item ) { if ( '' !== $this->get_item_context_key( $item ) ) { return ''; } $post = is_multisite() ? get_blog_post( $item['blog_id'], $item['ID'] ) : get_post( $item['ID'] ); if ( $post ) { $m_time = strtotime( $post->post_date ); $h_time = wp_date( get_option( 'date_format' ), $m_time ); return sprintf( '%1$s', esc_attr( $h_time ) ); } return ''; } /** * Handles the post_type column output. * * @param array $item Current item. * @return string Post Type. */ public function column_post_type( $item ) { if ( '' !== $this->get_item_context_key( $item ) ) { return esc_html__( 'Site-wide', 'top-10' ); } $post = is_multisite() ? get_blog_post( $item['blog_id'], $item['ID'] ) : get_post( $item['ID'] ); if ( $post ) { $pt = get_post_type_object( $post->post_type ); if ( empty( $pt ) ) { return $post->post_type; } $name = isset( $pt->labels->singular_name ) ? $pt->labels->singular_name : $pt->labels->name; return $name; } return ''; } /** * Handles the post author column output. * * @param array $item Current item. * @return string Post Author. */ public function column_author( $item ) { if ( '' !== $this->get_item_context_key( $item ) ) { return ''; } $post = is_multisite() ? get_blog_post( $item['blog_id'], $item['ID'] ) : get_post( $item['ID'] ); if ( ! $post ) { return ''; } $author_info = get_userdata( (int) $post->post_author ); $author_name = ( false === $author_info ) ? '' : ucwords( trim( stripslashes( $author_info->display_name ), " \t\n\r\0\x0B" ) ); return sprintf( '%s', esc_url( add_query_arg( array( 'post_type' => $post->post_type, 'author' => ( false === $author_info ) ? 0 : $author_info->ID, ), get_admin_url( $item['blog_id'], 'edit.php' ) ) ), esc_html( $author_name ) ); } /** * Render the Total Count column. * * @param array $item Current item. * @return string */ public function column_total_count( $item ) { if ( '' !== $this->get_item_context_key( $item ) ) { return \WebberZone\Top_Ten\Util\Helpers::number_format_i18n( absint( $item['total_count'] ) ); } return sprintf( '
%4$s
', $item['ID'], $item['total_count'], $this->network_wide ? ' data-wp-blog-id="' . esc_attr( $item['blog_id'] ) . '"' : '', \WebberZone\Top_Ten\Util\Helpers::number_format_i18n( absint( $item['total_count'] ) ) ); } /** * Handles the blog id column output. * * @param array $item Current item. * @return void */ public function column_blog_id( $item ) { $blog_details = get_blog_details( $item['blog_id'] ); printf( '%s', esc_url( add_query_arg( array( 'page' => 'tptn_popular_posts', ), get_admin_url( $item['blog_id'] ) . 'admin.php' ) ), esc_html( $blog_details->blogname ) ); } /** * Get the number of days spanned by the current post-date-filter-from/to request, * mirroring the default used in get_popular_posts() (today only when unset). * * @since 4.3.4 * * @return int Number of days, minimum 1. */ protected function get_current_filter_days() { $from_date = isset( $_REQUEST['post-date-filter-from'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['post-date-filter-from'] ) ) : current_time( 'd M Y' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $to_date = isset( $_REQUEST['post-date-filter-to'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['post-date-filter-to'] ) ) : current_time( 'd M Y' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $from_timestamp = strtotime( $from_date ); $to_timestamp = strtotime( $to_date ); if ( false === $from_timestamp || false === $to_timestamp ) { return 1; } $days = (int) round( ( $to_timestamp - $from_timestamp ) / DAY_IN_SECONDS ) + 1; return max( 1, $days ); } /** * Associative array of columns * * @return array */ public function get_columns() { $columns = array( 'cb' => '', 'title' => __( 'Title', 'top-10' ), 'total_count' => __( 'Total visits', 'top-10' ), /* translators: %s: Custom period label (e.g. Daily, Custom (7 days)). */ 'daily_count' => sprintf( __( '%s visits', 'top-10' ), Helpers::get_daily_range_label( $this->get_current_filter_days() ) ), 'post_type' => __( 'Post type', 'top-10' ), 'author' => __( 'Author', 'top-10' ), 'date' => __( 'Date', 'top-10' ), ); if ( $this->network_wide ) { $columns['blog_id'] = __( 'Blog', 'top-10' ); } /** * Filter the columns displayed in the Posts list table. * * @since 1.5.0 * * @param array $columns An array of column names. */ return apply_filters( 'manage_pop_posts_columns', $columns ); } /** * Columns to make sortable. * * @return array */ public function get_sortable_columns() { $sortable_columns = array( 'total_count' => array( 'total_count', true ), 'daily_count' => array( 'daily_count', true ), ); if ( ! $this->network_wide ) { $sortable_columns['title'] = array( 'title', false ); } return $sortable_columns; } /** * Returns an associative array containing the bulk action * * @return array */ public function get_bulk_actions() { $actions = array( 'bulk-delete' => __( 'Delete Count', 'top-10' ), ); return $actions; } /** * Handles data query and filter, sorting, and pagination. */ public function prepare_items() { $this->_column_headers = $this->get_column_info(); /** Process bulk action */ $this->process_bulk_action(); $per_page = $this->get_items_per_page( 'pop_posts_per_page', 20 ); $current_page = $this->get_pagenum(); $args = array(); // If this is a search? if ( isset( $_REQUEST['s'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $args['search'] = sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } // If this is a post type filter? if ( isset( $_REQUEST['post-type-filter'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $args['post-type-filter'] = sanitize_text_field( wp_unslash( $_REQUEST['post-type-filter'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } // If this is a post date filter? if ( isset( $_REQUEST['post-date-filter-to'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $args['post-date-filter-to'] = sanitize_text_field( wp_unslash( $_REQUEST['post-date-filter-to'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } if ( isset( $_REQUEST['post-date-filter-from'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $args['post-date-filter-from'] = sanitize_text_field( wp_unslash( $_REQUEST['post-date-filter-from'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } $this->items = self::get_popular_posts( $per_page, $current_page, $args ); $total_items = (int) self::record_count( $args ); $this->set_pagination_args( array( 'total_items' => $total_items, // WE have to calculate the total number of items. 'per_page' => $per_page, // WE have to determine how many items to show on a page. 'total_pages' => (int) ceil( $total_items / $per_page ), // WE have to calculate the total number of pages. ) ); } /** * Handles any bulk actions */ public function process_bulk_action() { // Detect when a bulk action is being triggered... if ( 'delete' === $this->current_action() ) { // In our file that handles the request, verify the nonce. $post_id = isset( $_GET['post'] ) ? absint( $_GET['post'] ) : 0; $blog_id = isset( $_GET['blog_id'] ) ? absint( $_GET['blog_id'] ) : get_current_blog_id(); if ( isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'tptn_delete_entry' ) ) { self::delete_post_count( $post_id, $blog_id ); } else { die( esc_html__( 'Are you sure you want to do this', 'top-10' ) ); } } // If the delete bulk action is triggered. if ( ( isset( $_REQUEST['action'] ) && 'bulk-delete' === $_REQUEST['action'] ) || ( isset( $_REQUEST['action2'] ) && 'bulk-delete' === $_REQUEST['action2'] ) ) { $delete_ids = isset( $_REQUEST['bulk-delete'] ) ? array_map( 'sanitize_text_field', (array) wp_unslash( $_REQUEST['bulk-delete'] ) ) : array(); // Loop over the array of record IDs and delete them. $post_ids = array(); $blog_ids = array(); foreach ( $delete_ids as $id ) { $pieces = explode( '-', $id ); $post_ids[] = absint( $pieces[0] ); $blog_ids[] = absint( $pieces[1] ); } \WebberZone\Top_Ten\Counter::delete_counts( array( 'post_id' => $post_ids, 'blog_id' => $blog_ids, 'daily' => true, ) ); \WebberZone\Top_Ten\Counter::delete_counts( array( 'post_id' => $post_ids, 'blog_id' => $blog_ids, 'daily' => false, ) ); } } /** * Adds extra navigation elements to the table. * * @param string $which Which part of the table are we. */ public function extra_tablenav( $which ) { ?>
'; $post_date_to = isset( $_REQUEST['post-date-filter-to'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['post-date-filter-to'] ) ) : $current_date; // phpcs:ignore WordPress.Security.NonceVerification.Recommended echo ''; if ( ! $this->network_wide ) { $post_types = get_post_types( array( 'public' => true, ) ); $post_types = $this->all_post_type + $post_types; if ( $post_types ) { echo '