652 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			652 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/**
 | 
						|
 * The Analytics module database operations
 | 
						|
 *
 | 
						|
 * @since      2.0.0
 | 
						|
 * @package    RankMathPro
 | 
						|
 * @subpackage RankMathPro\modules
 | 
						|
 * @author     Rank Math <support@rankmath.com>
 | 
						|
 */
 | 
						|
 | 
						|
namespace RankMathPro\Analytics;
 | 
						|
 | 
						|
use RankMath\Helper;
 | 
						|
use RankMath\Admin\Admin_Helper;
 | 
						|
use RankMath\Google\Analytics as Analytics_Free;
 | 
						|
use RankMath\Analytics\Stats;
 | 
						|
use RankMathPro\Google\Adsense;
 | 
						|
use RankMathPro\Analytics\Keywords;
 | 
						|
use MyThemeShop\Helpers\Str;
 | 
						|
use MyThemeShop\Database\Database;
 | 
						|
 | 
						|
defined( 'ABSPATH' ) || exit;
 | 
						|
 | 
						|
/**
 | 
						|
 * DB class.
 | 
						|
 */
 | 
						|
class DB {
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get any table.
 | 
						|
	 *
 | 
						|
	 * @param string $table_name Table name.
 | 
						|
	 *
 | 
						|
	 * @return \MyThemeShop\Database\Query_Builder
 | 
						|
	 */
 | 
						|
	public static function table( $table_name ) {
 | 
						|
		return Database::table( $table_name );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get console data table.
 | 
						|
	 *
 | 
						|
	 * @return \MyThemeShop\Database\Query_Builder
 | 
						|
	 */
 | 
						|
	public static function analytics() {
 | 
						|
		return Database::table( 'rank_math_analytics_gsc' );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get analytics data table.
 | 
						|
	 *
 | 
						|
	 * @return \MyThemeShop\Database\Query_Builder
 | 
						|
	 */
 | 
						|
	public static function traffic() {
 | 
						|
		return Database::table( 'rank_math_analytics_ga' );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get adsense data table.
 | 
						|
	 *
 | 
						|
	 * @return \MyThemeShop\Database\Query_Builder
 | 
						|
	 */
 | 
						|
	public static function adsense() {
 | 
						|
		return Database::table( 'rank_math_analytics_adsense' );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get objects table.
 | 
						|
	 *
 | 
						|
	 * @return \MyThemeShop\Database\Query_Builder
 | 
						|
	 */
 | 
						|
	public static function objects() {
 | 
						|
		return Database::table( 'rank_math_analytics_objects' );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get inspections table.
 | 
						|
	 *
 | 
						|
	 * @return \MyThemeShop\Database\Query_Builder
 | 
						|
	 */
 | 
						|
	public static function inspections() {
 | 
						|
		return Database::table( 'rank_math_analytics_inspections' );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get links table.
 | 
						|
	 *
 | 
						|
	 * @return \MyThemeShop\Database\Query_Builder
 | 
						|
	 */
 | 
						|
	public static function links() {
 | 
						|
		return Database::table( 'rank_math_internal_meta' );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get keywords table.
 | 
						|
	 *
 | 
						|
	 * @return \MyThemeShop\Database\Query_Builder
 | 
						|
	 */
 | 
						|
	public static function keywords() {
 | 
						|
		return Database::table( 'rank_math_analytics_keyword_manager' );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Delete console and analytics data.
 | 
						|
	 *
 | 
						|
	 * @param  int $days Decide whether to delete all or delete 90 days data.
 | 
						|
	 */
 | 
						|
	public static function delete_by_days( $days ) {
 | 
						|
		if ( -1 === $days ) {
 | 
						|
			self::traffic()->truncate();
 | 
						|
			self::analytics()->truncate();
 | 
						|
		} else {
 | 
						|
			$start = date_i18n( 'Y-m-d H:i:s', strtotime( '-1 days' ) );
 | 
						|
			$end   = date_i18n( 'Y-m-d H:i:s', strtotime( '-' . $days . ' days' ) );
 | 
						|
 | 
						|
			self::traffic()->whereBetween( 'created', [ $end, $start ] )->delete();
 | 
						|
			self::analytics()->whereBetween( 'created', [ $end, $start ] )->delete();
 | 
						|
		}
 | 
						|
		self::purge_cache();
 | 
						|
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Delete record for comparison.
 | 
						|
	 */
 | 
						|
	public static function delete_data_log() {
 | 
						|
		$days = Helper::get_settings( 'general.console_caching_control', 90 );
 | 
						|
 | 
						|
		$start = date_i18n( 'Y-m-d H:i:s', strtotime( '-' . ( $days * 2 ) . ' days' ) );
 | 
						|
 | 
						|
		self::traffic()->where( 'created', '<', $start )->delete();
 | 
						|
		self::analytics()->where( 'created', '<', $start )->delete();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Purge SC transient
 | 
						|
	 */
 | 
						|
	public static function purge_cache() {
 | 
						|
		$table = Database::table( 'options' );
 | 
						|
		$table->whereLike( 'option_name', 'rank_math_analytics_data_info' )->delete();
 | 
						|
		$table->whereLike( 'option_name', 'tracked_keywords_summary' )->delete();
 | 
						|
		$table->whereLike( 'option_name', 'top_keywords' )->delete();
 | 
						|
		$table->whereLike( 'option_name', 'top_keywords_graph' )->delete();
 | 
						|
		$table->whereLike( 'option_name', 'winning_keywords' )->delete();
 | 
						|
		$table->whereLike( 'option_name', 'losing_keywords' )->delete();
 | 
						|
		$table->whereLike( 'option_name', 'posts_summary' )->delete();
 | 
						|
		$table->whereLike( 'option_name', 'winning_posts' )->delete();
 | 
						|
		$table->whereLike( 'option_name', 'losing_posts' )->delete();
 | 
						|
 | 
						|
		wp_cache_flush();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get search console table info (for pro version only).
 | 
						|
	 *
 | 
						|
	 * @return array
 | 
						|
	 */
 | 
						|
	public static function info() {
 | 
						|
		global $wpdb;
 | 
						|
 | 
						|
		$key  = 'rank_math_analytics_data_info';
 | 
						|
		$data = get_transient( $key );
 | 
						|
		if ( false !== $data ) {
 | 
						|
			return $data;
 | 
						|
		}
 | 
						|
 | 
						|
		$days = 0;
 | 
						|
 | 
						|
		$rows = self::get_total_rows();
 | 
						|
 | 
						|
		$size = $wpdb->get_var( 'SELECT SUM((data_length + index_length)) AS size FROM information_schema.TABLES WHERE table_schema="' . $wpdb->dbname . '" AND table_name IN ( ' . '"' . $wpdb->prefix . 'rank_math_analytics_ga", "' . $wpdb->prefix . 'rank_math_analytics_adsense"' . ' )' ); // phpcs:ignore
 | 
						|
 | 
						|
		$data = compact( 'days', 'rows', 'size' );
 | 
						|
 | 
						|
		set_transient( $key, $data, DAY_IN_SECONDS );
 | 
						|
 | 
						|
		return $data;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get total row count of analytics and adsense tables
 | 
						|
	 *
 | 
						|
	 * @return int total row count
 | 
						|
	 */
 | 
						|
	public static function get_total_rows() {
 | 
						|
		$rows = 0;
 | 
						|
 | 
						|
		if ( Analytics_Free::is_analytics_connected() ) {
 | 
						|
			$rows += self::table( 'rank_math_analytics_ga' )
 | 
						|
				->selectCount( 'id' )
 | 
						|
				->getVar();
 | 
						|
		}
 | 
						|
 | 
						|
		if ( Adsense::is_adsense_connected() ) {
 | 
						|
			$rows += self::table( 'rank_math_analytics_adsense' )
 | 
						|
				->selectCount( 'id' )
 | 
						|
				->getVar();
 | 
						|
		}
 | 
						|
 | 
						|
		return $rows;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Has data pulled.
 | 
						|
	 *
 | 
						|
	 * @return boolean
 | 
						|
	 */
 | 
						|
	public static function has_data() {
 | 
						|
		static $rank_math_gsc_has_data;
 | 
						|
		if ( isset( $rank_math_gsc_has_data ) ) {
 | 
						|
			return $rank_math_gsc_has_data;
 | 
						|
		}
 | 
						|
 | 
						|
		$id = self::objects()
 | 
						|
			->select( 'id' )
 | 
						|
			->limit( 1 )
 | 
						|
			->getVar();
 | 
						|
 | 
						|
		$rank_math_gsc_has_data = $id > 0 ? true : false;
 | 
						|
		return $rank_math_gsc_has_data;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Add a new record into objects table.
 | 
						|
	 *
 | 
						|
	 * @param array $args Values to insert.
 | 
						|
	 *
 | 
						|
	 * @return bool|int
 | 
						|
	 */
 | 
						|
	public static function add_object( $args = [] ) {
 | 
						|
		if ( empty( $args ) ) {
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		$args = wp_parse_args(
 | 
						|
			$args,
 | 
						|
			[
 | 
						|
				'created'        => current_time( 'mysql' ),
 | 
						|
				'page'           => '',
 | 
						|
				'object_type'    => 'post',
 | 
						|
				'object_subtype' => 'post',
 | 
						|
				'object_id'      => 0,
 | 
						|
				'primary_key'    => '',
 | 
						|
				'seo_score'      => 0,
 | 
						|
				'page_score'     => 0,
 | 
						|
				'is_indexable'   => false,
 | 
						|
				'schemas_in_use' => '',
 | 
						|
			]
 | 
						|
		);
 | 
						|
 | 
						|
		return self::objects()->insert( $args, [ '%s', '%s', '%s', '%s', '%d', '%s', '%d', '%d', '%d', '%s' ] );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Add/Update a record into/from objects table.
 | 
						|
	 *
 | 
						|
	 * @param array $args Values to update.
 | 
						|
	 *
 | 
						|
	 * @return bool|int
 | 
						|
	 */
 | 
						|
	public static function update_object( $args = [] ) {
 | 
						|
		if ( empty( $args ) ) {
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		// If object exists, try to update.
 | 
						|
		$old_id = absint( $args['id'] );
 | 
						|
		if ( ! empty( $old_id ) ) {
 | 
						|
			unset( $args['id'] );
 | 
						|
 | 
						|
			$updated = self::objects()->set( $args )
 | 
						|
				->where( 'id', $old_id )
 | 
						|
				->where( 'object_id', absint( $args['object_id'] ) )
 | 
						|
				->update();
 | 
						|
 | 
						|
			if ( ! empty( $updated ) ) {
 | 
						|
				return $old_id;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// In case of new object or failed to update, try to add.
 | 
						|
		return self::add_object( $args );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Add console records.
 | 
						|
	 *
 | 
						|
	 * @param string $date Date of creation.
 | 
						|
	 * @param array  $rows Data rows to insert.
 | 
						|
	 */
 | 
						|
	public static function add_query_page_bulk( $date, $rows ) {
 | 
						|
		$chunks = array_chunk( $rows, 50 );
 | 
						|
 | 
						|
		foreach ( $chunks as $chunk ) {
 | 
						|
			self::bulk_insert_query_page_data( $date . ' 00:00:00', $chunk );
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Bulk inserts records into a table using WPDB.  All rows must contain the same keys.
 | 
						|
	 *
 | 
						|
	 * @param  string $date        Date.
 | 
						|
	 * @param  array  $rows        Rows to insert.
 | 
						|
	 */
 | 
						|
	public static function bulk_insert_query_page_data( $date, $rows ) {
 | 
						|
		global $wpdb;
 | 
						|
 | 
						|
		$data         = [];
 | 
						|
		$placeholders = [];
 | 
						|
		$columns      = [
 | 
						|
			'created',
 | 
						|
			'query',
 | 
						|
			'page',
 | 
						|
			'clicks',
 | 
						|
			'impressions',
 | 
						|
			'position',
 | 
						|
			'ctr',
 | 
						|
		];
 | 
						|
		$columns      = '`' . implode( '`, `', $columns ) . '`';
 | 
						|
		$placeholder  = [
 | 
						|
			'%s',
 | 
						|
			'%s',
 | 
						|
			'%s',
 | 
						|
			'%d',
 | 
						|
			'%d',
 | 
						|
			'%d',
 | 
						|
			'%d',
 | 
						|
		];
 | 
						|
 | 
						|
		// Start building SQL, initialise data and placeholder arrays.
 | 
						|
		$sql = "INSERT INTO `{$wpdb->prefix}rank_math_analytics_gsc` ( $columns ) VALUES\n";
 | 
						|
 | 
						|
		// Build placeholders for each row, and add values to data array.
 | 
						|
		foreach ( $rows as $row ) {
 | 
						|
			if (
 | 
						|
				$row['position'] > self::get_position_filter() ||
 | 
						|
				Str::contains( '?', $row['page'] )
 | 
						|
			) {
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			$data[] = $date;
 | 
						|
			$data[] = $row['query'];
 | 
						|
			$data[] = Stats::get_relative_url( self::remove_hash( $row['page'] ) );
 | 
						|
			$data[] = $row['clicks'];
 | 
						|
			$data[] = $row['impressions'];
 | 
						|
			$data[] = $row['position'];
 | 
						|
			$data[] = $row['ctr'];
 | 
						|
 | 
						|
			$placeholders[] = '(' . implode( ', ', $placeholder ) . ')';
 | 
						|
		}
 | 
						|
 | 
						|
		// Don't run insert with empty dataset, return 0 since no rows affected.
 | 
						|
		if ( empty( $data ) ) {
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
 | 
						|
		// Stitch all rows together.
 | 
						|
		$sql .= implode( ",\n", $placeholders );
 | 
						|
 | 
						|
		// Run the query.  Returns number of affected rows.
 | 
						|
		return $wpdb->query( $wpdb->prepare( $sql, $data ) ); // phpcs:ignore
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Add analytic records.
 | 
						|
	 *
 | 
						|
	 * @param string $date Date of creation.
 | 
						|
	 * @param array  $rows Data rows to insert.
 | 
						|
	 */
 | 
						|
	public static function add_analytics_bulk( $date, $rows ) {
 | 
						|
		$chunks = array_chunk( $rows, 50 );
 | 
						|
 | 
						|
		foreach ( $chunks as $chunk ) {
 | 
						|
			self::bulk_insert_analytics_data( $date . ' 00:00:00', $chunk );
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Bulk inserts records into a table using WPDB.  All rows must contain the same keys.
 | 
						|
	 *
 | 
						|
	 * @param  string $date        Date.
 | 
						|
	 * @param  array  $rows        Rows to insert.
 | 
						|
	 */
 | 
						|
	public static function bulk_insert_analytics_data( $date, $rows ) {
 | 
						|
		global $wpdb;
 | 
						|
 | 
						|
		$data         = [];
 | 
						|
		$placeholders = [];
 | 
						|
		$columns      = [
 | 
						|
			'created',
 | 
						|
			'page',
 | 
						|
			'pageviews',
 | 
						|
			'visitors',
 | 
						|
		];
 | 
						|
		$columns      = '`' . implode( '`, `', $columns ) . '`';
 | 
						|
		$placeholder  = [
 | 
						|
			'%s',
 | 
						|
			'%s',
 | 
						|
			'%d',
 | 
						|
			'%d',
 | 
						|
		];
 | 
						|
 | 
						|
		// Start building SQL, initialise data and placeholder arrays.
 | 
						|
		$sql = "INSERT INTO `{$wpdb->prefix}rank_math_analytics_ga` ( $columns ) VALUES\n";
 | 
						|
 | 
						|
		// Build placeholders for each row, and add values to data array.
 | 
						|
		foreach ( $rows as $row ) {
 | 
						|
			$page      = '';
 | 
						|
			$pageviews = '';
 | 
						|
			$visitors  = '';
 | 
						|
 | 
						|
			if ( ! isset( $row['dimensionValues'] ) ) {
 | 
						|
				if ( empty( $row['dimensions'][1] ) || Str::contains( '?', $row['dimensions'][1] ) ) {
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
				$page      = $row['dimensions'][2] . $row['dimensions'][1];
 | 
						|
				$pageviews = $row['metrics'][0]['values'][0];
 | 
						|
				$visitors  = $row['metrics'][0]['values'][1];
 | 
						|
			} else {
 | 
						|
				if ( empty( $row['dimensionValues'][1]['value'] ) || Str::contains( '?', $row['dimensionValues'][1]['value'] ) ) {
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
				$page      = $row['dimensionValues'][0]['value'] . $row['dimensionValues'][1]['value'];
 | 
						|
				$pageviews = $row['metricValues'][0]['value'];
 | 
						|
				$visitors  = $row['metricValues'][1]['value'];
 | 
						|
			}
 | 
						|
 | 
						|
			if ( $page && $pageviews && $visitors ) {
 | 
						|
				$page = ( is_ssl() ? 'https' : 'http' ) . '://' . $page;
 | 
						|
 | 
						|
				$data[] = $date;
 | 
						|
				$data[] = Stats::get_relative_url( self::remove_hash( $page ) );
 | 
						|
				$data[] = $pageviews;
 | 
						|
				$data[] = $visitors;
 | 
						|
 | 
						|
				$placeholders[] = '(' . implode( ', ', $placeholder ) . ')';
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if ( empty( $placeholders ) ) {
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
 | 
						|
		// Stitch all rows together.
 | 
						|
		$sql .= implode( ",\n", $placeholders );
 | 
						|
 | 
						|
		// Run the query.  Returns number of affected rows.
 | 
						|
		return $wpdb->query( $wpdb->prepare( $sql, $data ) ); // phpcs:ignore
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Remove hash part from Url.
 | 
						|
	 *
 | 
						|
	 * @param  string $url Url to process.
 | 
						|
	 * @return string
 | 
						|
	 */
 | 
						|
	public static function remove_hash( $url ) {
 | 
						|
		if ( ! Str::contains( '#', $url ) ) {
 | 
						|
			return $url;
 | 
						|
		}
 | 
						|
 | 
						|
		$url = \explode( '#', $url );
 | 
						|
		return $url[0];
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Add adsense records.
 | 
						|
	 *
 | 
						|
	 * @param array $rows Data rows to insert.
 | 
						|
	 */
 | 
						|
	public static function add_adsense( $rows ) {
 | 
						|
		if ( ! \MyThemeShop\Helpers\DB::check_table_exists( 'rank_math_analytics_adsense' ) ) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		foreach ( $rows as $row ) {
 | 
						|
			$date     = $row['cells'][0]['value'];
 | 
						|
			$earnings = floatval( $row['cells'][1]['value'] );
 | 
						|
 | 
						|
			self::adsense()
 | 
						|
				->insert(
 | 
						|
					[
 | 
						|
						'created'  => $date . ' 00:00:00',
 | 
						|
						'earnings' => $earnings,
 | 
						|
					],
 | 
						|
					[ '%s', '%f' ]
 | 
						|
				);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get position filter.
 | 
						|
	 *
 | 
						|
	 * @return int
 | 
						|
	 */
 | 
						|
	private static function get_position_filter() {
 | 
						|
		$number = apply_filters( 'rank_math/analytics/position_limit', false );
 | 
						|
		if ( false === $number ) {
 | 
						|
			return 100;
 | 
						|
		}
 | 
						|
 | 
						|
		return $number;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Bulk inserts records into a keyword table using WPDB.  All rows must contain the same keys.
 | 
						|
	 *
 | 
						|
	 * @param array $rows Rows to insert.
 | 
						|
	 */
 | 
						|
	public static function bulk_insert_query_focus_keyword_data( $rows ) {
 | 
						|
		$registered = Admin_Helper::get_registration_data();
 | 
						|
		if ( ! $registered || empty( $registered['username'] ) || empty( $registered['api_key'] ) ) {
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		// Check remain keywords count can be added.
 | 
						|
		$total_keywords = Keywords::get()->get_tracked_keywords_count();
 | 
						|
		$new_keywords   = Keywords::get()->extract_addable_track_keyword( implode( ',', $rows ) );
 | 
						|
		$keywords_count = count( $new_keywords );
 | 
						|
		if ( $keywords_count <= 0 ) {
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		$summary = Keywords::get()->get_tracked_keywords_quota();
 | 
						|
		$remain  = $summary['available'] - $total_keywords;
 | 
						|
		if ( $remain <= 0 ) {
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		// Add remaining limit keywords.
 | 
						|
		$new_keywords = array_slice( $new_keywords, 0, $remain );
 | 
						|
 | 
						|
		$data         = [];
 | 
						|
		$placeholders = [];
 | 
						|
		$columns      = [
 | 
						|
			'keyword',
 | 
						|
			'collection',
 | 
						|
			'is_active',
 | 
						|
		];
 | 
						|
		$columns      = '`' . implode( '`, `', $columns ) . '`';
 | 
						|
		$placeholder  = [
 | 
						|
			'%s',
 | 
						|
			'%s',
 | 
						|
			'%s',
 | 
						|
		];
 | 
						|
 | 
						|
		// Start building SQL, initialise data and placeholder arrays.
 | 
						|
		global $wpdb;
 | 
						|
		$sql = "INSERT INTO `{$wpdb->prefix}rank_math_analytics_keyword_manager` ( $columns ) VALUES\n";
 | 
						|
 | 
						|
		// Build placeholders for each row, and add values to data array.
 | 
						|
		foreach ( $new_keywords as $new_keyword ) {
 | 
						|
			$data[]         = $new_keyword;
 | 
						|
			$data[]         = 'uncategorized';
 | 
						|
			$data[]         = 1;
 | 
						|
			$placeholders[] = '(' . implode( ', ', $placeholder ) . ')';
 | 
						|
		}
 | 
						|
 | 
						|
		// Stitch all rows together.
 | 
						|
		$sql .= implode( ",\n", $placeholders );
 | 
						|
 | 
						|
		// Run the query.  Returns number of affected rows.
 | 
						|
		$count = $wpdb->query( $wpdb->prepare( $sql, $data ) ); // phpcs:ignore
 | 
						|
 | 
						|
		$total_keywords = Keywords::get()->get_tracked_keywords_count();
 | 
						|
		$response       = \RankMathPro\Admin\Api::get()->keywords_info( $registered['username'], $registered['api_key'], $total_keywords );
 | 
						|
		if ( $response ) {
 | 
						|
			update_option( 'rank_math_keyword_quota', $response );
 | 
						|
		}
 | 
						|
 | 
						|
		return $count;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get stats from DB for "Presence on Google" widget:
 | 
						|
	 * All unique coverage_state values and their counts.
 | 
						|
	 */
 | 
						|
	public static function get_presence_stats() {
 | 
						|
		$results = self::inspections()
 | 
						|
			->select(
 | 
						|
				[
 | 
						|
					'coverage_state',
 | 
						|
					'COUNT(*)' => 'count',
 | 
						|
				]
 | 
						|
			)
 | 
						|
			->groupBy( 'coverage_state' )
 | 
						|
			->orderBy( 'count', 'DESC' )
 | 
						|
			->get();
 | 
						|
 | 
						|
		$results = array_map(
 | 
						|
			'absint',
 | 
						|
			array_combine(
 | 
						|
				array_column( $results, 'coverage_state' ),
 | 
						|
				array_column( $results, 'count' )
 | 
						|
			)
 | 
						|
		);
 | 
						|
 | 
						|
		return $results;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get stats from DB for "Top Statuses" widget.
 | 
						|
	 */
 | 
						|
	public static function get_status_stats() {
 | 
						|
		$statuses = [
 | 
						|
			'VERDICT_UNSPECIFIED',
 | 
						|
			'PASS',
 | 
						|
			'PARTIAL',
 | 
						|
			'FAIL',
 | 
						|
			'NEUTRAL',
 | 
						|
		];
 | 
						|
 | 
						|
		// Get all unique index_verdict values and their counts.
 | 
						|
		$index_statuses = self::inspections()
 | 
						|
			->select(
 | 
						|
				[
 | 
						|
					'index_verdict',
 | 
						|
					'COUNT(*)' => 'count',
 | 
						|
				]
 | 
						|
			)
 | 
						|
			->groupBy( 'index_verdict' )
 | 
						|
			->orderBy( 'count', 'DESC' )
 | 
						|
			->get();
 | 
						|
 | 
						|
		$results = array_fill_keys( $statuses, 0 );
 | 
						|
		foreach ( $index_statuses as $status ) {
 | 
						|
			if ( empty( $status->index_verdict ) ) {
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			$results[ $status->index_verdict ] += $status->count;
 | 
						|
		}
 | 
						|
 | 
						|
		return $results;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get stats from DB for "Top Statuses" widget.
 | 
						|
	 */
 | 
						|
	public static function get_index_verdict( $page ) {
 | 
						|
		$verdict = self::inspections()
 | 
						|
			->select()
 | 
						|
			->where( 'page', '=', $page )
 | 
						|
			->one();
 | 
						|
 | 
						|
		return (array) $verdict;
 | 
						|
	}
 | 
						|
}
 |