323 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			323 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/**
 | 
						|
 * Jobs.
 | 
						|
 *
 | 
						|
 * @since      1.0.54
 | 
						|
 * @package    RankMath
 | 
						|
 * @subpackage RankMath\modules
 | 
						|
 * @author     Rank Math <support@rankmath.com>
 | 
						|
 */
 | 
						|
 | 
						|
namespace RankMath\Analytics\Workflow;
 | 
						|
 | 
						|
use Exception;
 | 
						|
use RankMath\Helper;
 | 
						|
use RankMath\Google\Api;
 | 
						|
use RankMath\Google\Console;
 | 
						|
use RankMath\Google\Url_Inspection;
 | 
						|
use RankMath\Analytics\DB;
 | 
						|
use RankMath\Traits\Cache;
 | 
						|
use RankMath\Traits\Hooker;
 | 
						|
use RankMath\Analytics\Stats;
 | 
						|
use RankMath\Analytics\Watcher;
 | 
						|
 | 
						|
defined( 'ABSPATH' ) || exit;
 | 
						|
 | 
						|
/**
 | 
						|
 * Jobs class.
 | 
						|
 */
 | 
						|
class Jobs {
 | 
						|
 | 
						|
	use Hooker, Cache;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Main instance
 | 
						|
	 *
 | 
						|
	 * Ensure only one instance is loaded or can be loaded.
 | 
						|
	 *
 | 
						|
	 * @return Jobs
 | 
						|
	 */
 | 
						|
	public static function get() {
 | 
						|
		static $instance;
 | 
						|
 | 
						|
		if ( is_null( $instance ) && ! ( $instance instanceof Jobs ) ) {
 | 
						|
			$instance = new Jobs();
 | 
						|
			$instance->hooks();
 | 
						|
		}
 | 
						|
 | 
						|
		return $instance;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Hooks.
 | 
						|
	 */
 | 
						|
	public function hooks() {
 | 
						|
		$this->action( 'rank_math/analytics/flat_posts', 'do_flat_posts' );
 | 
						|
		$this->action( 'rank_math/analytics/flat_posts_completed', 'flat_posts_completed' );
 | 
						|
		add_action( 'rank_math/analytics/sync_sitemaps', [ Api::get(), 'sync_sitemaps' ] );
 | 
						|
 | 
						|
		if ( Console::is_console_connected() ) {
 | 
						|
			$this->action( 'rank_math/analytics/clear_cache', 'clear_cache', 99 );
 | 
						|
 | 
						|
			// Fetch missing google data action.
 | 
						|
			$this->action( 'rank_math/analytics/data_fetch', 'data_fetch' );
 | 
						|
 | 
						|
			// Console data fetch.
 | 
						|
			$this->filter( 'rank_math/analytics/get_console_days', 'get_console_days' );
 | 
						|
			$this->action( 'rank_math/analytics/get_console_data', 'get_console_data' );
 | 
						|
			$this->action( 'rank_math/analytics/handle_console_response', 'handle_console_response' );
 | 
						|
 | 
						|
			// Inspections data fetch.
 | 
						|
			$this->action( 'rank_math/analytics/get_inspections_data', 'get_inspections_data' );
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Fetch missing console data.
 | 
						|
	 */
 | 
						|
	public function data_fetch() {
 | 
						|
		$this->check_for_missing_dates( 'console' );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Perform post check.
 | 
						|
	 */
 | 
						|
	public function flat_posts_completed() {
 | 
						|
		$rows = DB::objects()
 | 
						|
			->selectCount( 'id' )
 | 
						|
			->getVar();
 | 
						|
 | 
						|
		Workflow::kill_workflows();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Add/update posts info from objects table.
 | 
						|
	 *
 | 
						|
	 * @param  array $ids Posts ids to process.
 | 
						|
	 */
 | 
						|
	public function do_flat_posts( $ids ) {
 | 
						|
		Inspections::kill_jobs();
 | 
						|
 | 
						|
		foreach ( $ids as $id ) {
 | 
						|
			Watcher::get()->update_post_info( $id );
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Clear cache.
 | 
						|
	 */
 | 
						|
	public function clear_cache() {
 | 
						|
		global $wpdb;
 | 
						|
 | 
						|
		// Delete all useless data from console data table.
 | 
						|
		$wpdb->get_results( "DELETE FROM {$wpdb->prefix}rank_math_analytics_gsc WHERE page NOT IN ( SELECT page from {$wpdb->prefix}rank_math_analytics_objects )" );
 | 
						|
 | 
						|
		// Delete useless data from inspections table too.
 | 
						|
		$wpdb->get_results( "DELETE FROM {$wpdb->prefix}rank_math_analytics_inspections WHERE page NOT IN ( SELECT page from {$wpdb->prefix}rank_math_analytics_objects )" );
 | 
						|
 | 
						|
		delete_transient( 'rank_math_analytics_data_info' );
 | 
						|
		DB::purge_cache();
 | 
						|
		DB::delete_data_log();
 | 
						|
		$this->calculate_stats();
 | 
						|
 | 
						|
		update_option( 'rank_math_analytics_last_updated', time() );
 | 
						|
 | 
						|
		Workflow::do_workflow( 'inspections' );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Set the console start and end dates.
 | 
						|
	 *
 | 
						|
	 * @param array $args Args containing start and end date.
 | 
						|
	 */
 | 
						|
	public function get_console_days( $args = [] ) {
 | 
						|
		set_time_limit( 300 );
 | 
						|
 | 
						|
		$rows = Api::get()->get_search_analytics(
 | 
						|
			[
 | 
						|
				'start_date' => $args['start_date'],
 | 
						|
				'end_date'   => $args['end_date'],
 | 
						|
				'dimensions' => [ 'date' ],
 | 
						|
			]
 | 
						|
		);
 | 
						|
 | 
						|
		if ( empty( $rows ) || is_wp_error( $rows ) ) {
 | 
						|
			return [];
 | 
						|
		}
 | 
						|
 | 
						|
		$empty_dates = get_option( 'rank_math_console_empty_dates', [] );
 | 
						|
 | 
						|
		$dates = [];
 | 
						|
 | 
						|
		foreach ( $rows as $row ) {
 | 
						|
 | 
						|
			// Have at least few impressions.
 | 
						|
			if ( $row['impressions'] ) {
 | 
						|
				$date = $row['keys'][0];
 | 
						|
 | 
						|
				if ( ! DB::date_exists( $date, 'console' ) && ! in_array( $date, $empty_dates, true ) ) {
 | 
						|
					$dates[] = [
 | 
						|
						'start_date' => $date,
 | 
						|
						'end_date'   => $date,
 | 
						|
					];
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return $dates;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get console data.
 | 
						|
	 *
 | 
						|
	 * @param string $date Date to fetch data for.
 | 
						|
	 */
 | 
						|
	public function get_console_data( $date ) {
 | 
						|
		set_time_limit( 300 );
 | 
						|
 | 
						|
		$rows = Api::get()->get_search_analytics(
 | 
						|
			[
 | 
						|
				'start_date' => $date,
 | 
						|
				'end_date'   => $date,
 | 
						|
				'dimensions' => [ 'query', 'page' ],
 | 
						|
			]
 | 
						|
		);
 | 
						|
 | 
						|
		if ( empty( $rows ) || is_wp_error( $rows ) ) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		$rows = \array_map( [ $this, 'normalize_query_page_data' ], $rows );
 | 
						|
 | 
						|
		try {
 | 
						|
			DB::add_query_page_bulk( $date, $rows );
 | 
						|
 | 
						|
			// Clear the cache here.
 | 
						|
			$this->cache_flush_group( 'rank_math_rest_keywords_rows' );
 | 
						|
			$this->cache_flush_group( 'rank_math_posts_rows_by_objects' );
 | 
						|
			$this->cache_flush_group( 'rank_math_analytics_summary' );
 | 
						|
 | 
						|
			return $rows;
 | 
						|
		} catch ( Exception $e ) {} // phpcs:ignore
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Handlle console response.
 | 
						|
	 *
 | 
						|
	 * @param array $data API request and response data.
 | 
						|
	 */
 | 
						|
	public function handle_console_response( $data = [] ) {
 | 
						|
		if ( 200 !== $data['code'] ) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		if ( isset( $data['formatted_response']['rows'] ) && ! empty( $data['formatted_response']['rows'] ) ) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		if ( ! isset( $data['args']['startDate'] ) ) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		$dates = get_option( 'rank_math_console_empty_dates', [] );
 | 
						|
		if ( ! $dates ) {
 | 
						|
			$dates = [];
 | 
						|
		}
 | 
						|
 | 
						|
		$dates[] = $data['args']['startDate'];
 | 
						|
		$dates[] = $data['args']['endDate'];
 | 
						|
 | 
						|
		$dates = array_unique( $dates );
 | 
						|
 | 
						|
		update_option( 'rank_math_console_empty_dates', $dates );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get inspection results from the API and store them in the database.
 | 
						|
	 *
 | 
						|
	 * @param string $page URI to fetch data for.
 | 
						|
	 */
 | 
						|
	public function get_inspections_data( $page ) {
 | 
						|
		// If the option is disabled, don't fetch data.
 | 
						|
		if ( ! \RankMath\Analytics\Url_Inspection::is_enabled() ) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		$inspection = Url_Inspection::get()->get_inspection_data( $page );
 | 
						|
		if ( empty( $inspection ) ) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		try {
 | 
						|
			DB::store_inspection( $inspection );
 | 
						|
		} catch ( Exception $e ) {} // phpcs:ignore
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Check for missing dates.
 | 
						|
	 *
 | 
						|
	 * @param string $action Action to perform.
 | 
						|
	 */
 | 
						|
	public function check_for_missing_dates( $action ) {
 | 
						|
		$days = Helper::get_settings( 'general.console_caching_control', 90 );
 | 
						|
 | 
						|
		Workflow::do_workflow(
 | 
						|
			$action,
 | 
						|
			$days,
 | 
						|
			null,
 | 
						|
			null
 | 
						|
		);
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Calculate stats.
 | 
						|
	 */
 | 
						|
	private function calculate_stats() {
 | 
						|
		$ranges = [
 | 
						|
			'-7 days',
 | 
						|
			'-15 days',
 | 
						|
			'-30 days',
 | 
						|
			'-3 months',
 | 
						|
			'-6 months',
 | 
						|
			'-1 year',
 | 
						|
		];
 | 
						|
 | 
						|
		foreach ( $ranges as $range ) {
 | 
						|
			Stats::get()->set_date_range( $range );
 | 
						|
			Stats::get()->get_top_keywords();
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Normalize console data.
 | 
						|
	 *
 | 
						|
	 * @param array $row Single row item.
 | 
						|
	 *
 | 
						|
	 * @return array
 | 
						|
	 */
 | 
						|
	protected function normalize_query_page_data( $row ) {
 | 
						|
		$row          = $this->normalize_data( $row );
 | 
						|
		$row['query'] = $row['keys'][0];
 | 
						|
		$row['page']  = $row['keys'][1];
 | 
						|
 | 
						|
		unset( $row['keys'] );
 | 
						|
 | 
						|
		return $row;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Normalize console data.
 | 
						|
	 *
 | 
						|
	 * @param array $row Single row item.
 | 
						|
	 *
 | 
						|
	 * @return array
 | 
						|
	 */
 | 
						|
	private function normalize_data( $row ) {
 | 
						|
		$row['ctr']      = round( $row['ctr'] * 100, 2 );
 | 
						|
		$row['position'] = round( $row['position'], 2 );
 | 
						|
 | 
						|
		return $row;
 | 
						|
	}
 | 
						|
}
 |