You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
8.0 KiB
PHP

<?php
/**
* Jobs.
*
* @since 1.0.54
* @package RankMathPro
* @subpackage RankMathPro\modules
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Analytics\Workflow;
use DateTime;
use Exception;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMathPro\Analytics\DB;
use RankMath\Analytics\Workflow\Base;
use RankMath\Analytics\DB as AnalyticsDB;
use RankMathPro\Google\Adsense;
use RankMath\Google\Analytics;
use RankMath\Analytics\Workflow\Jobs as AnalyticsJobs;
defined( 'ABSPATH' ) || exit;
/**
* Jobs class.
*/
class Jobs {
use Hooker;
/**
* Is an Analytics account connected?
*
* @var boolean
*/
private $analytics_connected = false;
/**
* Is an AdSense account connected?
*
* @var boolean
*/
private $adsense_connected = false;
/**
* 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->analytics_connected = Analytics::is_analytics_connected();
$this->adsense_connected = \RankMathPro\Google\Adsense::is_adsense_connected();
// Check missing data for analytics and adsense.
$this->action( 'rank_math/analytics/data_fetch', 'data_fetch' );
// Data Fetcher.
if ( $this->adsense_connected ) {
$this->filter( 'rank_math/analytics/get_adsense_days', 'get_adsense_days' );
$this->action( 'rank_math/analytics/get_adsense_data', 'get_adsense_data', 10, 2 );
}
if ( $this->analytics_connected ) {
$this->action( 'rank_math/analytics/get_analytics_days', 'get_analytics_days' );
$this->action( 'rank_math/analytics/get_analytics_data', 'get_analytics_data' );
$this->action( 'rank_math/analytics/handle_analytics_response', 'handle_analytics_response' );
$this->action( 'rank_math/analytics/clear_cache', 'clear_cache' );
}
// Cache.
$this->action( 'rank_math/analytics/purge_cache', 'purge_cache' );
$this->action( 'rank_math/analytics/delete_by_days', 'delete_by_days' );
$this->action( 'rank_math/analytics/delete_data_log', 'delete_data_log' );
}
/**
* Check missing data for analytics and adsense. Perform this task periodically.
*/
public function data_fetch() {
if ( $this->analytics_connected ) {
AnalyticsJobs::get()->check_for_missing_dates( 'analytics' );
}
if ( $this->adsense_connected ) {
AnalyticsJobs::get()->check_for_missing_dates( 'adsense' );
}
}
/**
* Set the analytics start and end dates.
*/
public function get_analytics_days( $args = [] ) {
$rows = Analytics::get_analytics(
[
'start_date' => $args['start_date'],
'end_date' => $args['end_date'],
],
true
);
if ( is_wp_error( $rows ) || empty( $rows ) ) {
return [];
}
$empty_dates = get_option( 'rank_math_analytics_empty_dates', [] );
$dates = [];
foreach ( $rows as $row ) {
$date = '';
// GA4
if ( isset( $row['dimensionValues'] ) ) {
$date = $row['dimensionValues'][0]['value'];
} elseif ( isset( $row['dimensions'] ) ) {
$date = $row['dimensions'][0];
}
if ( ! empty( $date ) ) {
$date = substr( $date, 0, 4 ) . '-' . substr( $date, 4, 2 ) . '-' . substr( $date, 6, 2 );
if ( ! AnalyticsDB::date_exists( $date, 'analytics' ) && ! in_array( $date, $empty_dates, true ) ) {
$dates[] = [
'start_date' => $date,
'end_date' => $date,
];
}
}
}
return $dates;
}
/**
* Get analytics data and save it into database.
*
* @param string $date Date to fetch data for.
*/
public function get_analytics_data( $date ) {
$rows = Analytics::get_analytics(
[
'start_date' => $date,
'end_date' => $date,
]
);
if ( is_wp_error( $rows ) || empty( $rows ) ) {
return [];
}
try {
DB::add_analytics_bulk( $date, $rows );
return $rows;
} catch ( Exception $e ) {} // phpcs:ignore
}
/**
* Set the AdSense start and end dates.
*/
public function get_adsense_days( $args = [] ) {
$dates = [];
$begin = new DateTime( $args['start_date'] );
$end = new DateTime( $args['end_date'] );
$missing_dates = [];
for ( $i = $end; $i >= $begin; $i->modify( '-1 day' ) ) {
$date = $i->format( 'Y-m-d' );
if ( ! AnalyticsDB::date_exists( $date, 'adsense' ) ) {
$missing_dates[] = $date;
}
}
if ( empty( $missing_dates ) ) {
$dates[] = [
'start_date' => $args['start_date'],
'end_date' => $args['end_date'],
];
return $dates;
}
// Request for one date range because its not large data to send individual request for each date.
$dates[] = [
'start_date' => $missing_dates[ count( $missing_dates ) - 1 ],
'end_date' => $missing_dates[0],
];
return $dates;
}
/**
* Get adsense data and save it into database.
*
* @param string $start_date The start date to fetch.
* @param string $end_date The end date to fetch.
*/
public function get_adsense_data( $start_date = '', $end_date = '' ) {
$rows = Adsense::get_adsense(
[
'start_date' => $start_date,
'end_date' => $end_date,
]
);
if ( is_wp_error( $rows ) || empty( $rows ) ) {
return [];
}
try {
DB::add_adsense( $rows );
return $rows;
} catch ( Exception $e ) {} // phpcs:ignore
}
/**
* Handlle analytics response.
*
* @param array $data API request and response data.
*/
public function handle_analytics_response( $data = [] ) {
if ( 200 !== $data['code'] ) {
return;
}
if ( isset( $data['formatted_response']['rows'] ) && ! empty( $data['formatted_response']['rows'] ) ) {
return;
}
$dates = get_option( 'rank_math_analytics_empty_dates', [] );
if ( ! $dates ) {
$dates = [];
}
$dates[] = $data['args']['dateRanges'][0]['startDate'];
$dates[] = $data['args']['dateRanges'][0]['endDate'];
$dates = array_unique( $dates );
update_option( 'rank_math_analytics_empty_dates', $dates );
}
/**
* Clear cache.
*/
public function clear_cache() {
global $wpdb;
// Delete all useless data from analytics data table.
$wpdb->get_results( "DELETE FROM {$wpdb->prefix}rank_math_analytics_ga WHERE page NOT IN ( SELECT page from {$wpdb->prefix}rank_math_analytics_objects )" );
}
/**
* Purge cache.
*
* @param object $table Table insance.
*/
public function purge_cache( $table ) {
$table->whereLike( 'option_name', 'losing_posts' )->delete();
$table->whereLike( 'option_name', 'winning_posts' )->delete();
$table->whereLike( 'option_name', 'losing_keywords' )->delete();
$table->whereLike( 'option_name', 'winning_keywords' )->delete();
$table->whereLike( 'option_name', 'tracked_keywords_summary' )->delete();
}
/**
* Delete analytics and adsense data by days.
*
* @param int $days Decide whether to delete all or delete 90 days data.
*/
public function delete_by_days( $days ) {
if ( -1 === $days ) {
if ( $this->analytics_connected ) {
DB::traffic()->truncate();
}
if ( $this->adsense_connected ) {
DB::adsense()->truncate();
}
return;
}
$start = date_i18n( 'Y-m-d H:i:s', strtotime( '-1 days' ) );
$end = date_i18n( 'Y-m-d H:i:s', strtotime( '-' . $days . ' days' ) );
if ( $this->analytics_connected ) {
DB::traffic()->whereBetween( 'created', [ $end, $start ] )->delete();
}
if ( $this->adsense_connected ) {
DB::adsense()->whereBetween( 'created', [ $end, $start ] )->delete();
}
}
/**
* Delete record for comparison.
*
* @param string $start Start date.
*/
public function delete_data_log( $start ) {
if ( $this->analytics_connected ) {
DB::traffic()->where( 'created', '<', $start )->delete();
}
if ( $this->adsense_connected ) {
DB::adsense()->where( 'created', '<', $start )->delete();
}
}
}