761 lines
24 KiB
PHP
761 lines
24 KiB
PHP
<?php
|
|
namespace AIOSEO\Plugin\Pro\SearchStatistics;
|
|
|
|
// Exit if accessed directly.
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
use AIOSEO\Plugin\Common\SearchStatistics as CommonSearchStatistics;
|
|
|
|
/**
|
|
* Class that holds our Search Statistics feature.
|
|
*
|
|
* @since 4.3.0
|
|
*/
|
|
class SearchStatistics extends CommonSearchStatistics\SearchStatistics {
|
|
/**
|
|
* Holds the instance of the Stats class.
|
|
*
|
|
* @since 4.3.0
|
|
*
|
|
* @var Stats\Stats
|
|
*/
|
|
public $stats = null;
|
|
|
|
/**
|
|
* Holds the instance of the Helpers class.
|
|
*
|
|
* @since 4.3.0
|
|
*
|
|
* @var Helpers
|
|
*/
|
|
public $helpers = null;
|
|
|
|
/**
|
|
* Holds the instance of the Objects class.
|
|
*
|
|
* @since 4.3.3
|
|
*
|
|
* @var Objects
|
|
*/
|
|
public $objects = null;
|
|
|
|
/**
|
|
* Holds the instance of the UrlInspection class.
|
|
*
|
|
* @since 4.5.0
|
|
*
|
|
* @var UrlInspection
|
|
*/
|
|
public $urlInspection = null;
|
|
|
|
/**
|
|
* Holds the instance of the PageSpeed class.
|
|
*
|
|
* @since 4.3.0
|
|
*
|
|
* @var PageSpeed
|
|
*/
|
|
public $pageSpeed;
|
|
|
|
/**
|
|
* Holds the instance of the Markers class.
|
|
*
|
|
* @since 4.3.0
|
|
*
|
|
* @var Markers
|
|
*/
|
|
public $markers;
|
|
|
|
/**
|
|
* Holds the instance of the Keyword Rank Tracker class.
|
|
*
|
|
* @since 4.7.0
|
|
*
|
|
* @var KeywordRankTracker
|
|
*/
|
|
public $keywordRankTracker;
|
|
|
|
/**
|
|
* Holds the instance of the Related Keywords class.
|
|
*
|
|
* @since 4.7.8
|
|
*
|
|
* @var RelatedKeywords
|
|
*/
|
|
public $relatedKeywords;
|
|
|
|
/**
|
|
* Holds the instance of the Index Status class.
|
|
*
|
|
* @since 4.8.2
|
|
*
|
|
* @var IndexStatus
|
|
*/
|
|
public $indexStatus;
|
|
|
|
/**
|
|
* Class constructor.
|
|
*
|
|
* @since 4.3.0
|
|
*/
|
|
public function __construct() {
|
|
parent::__construct();
|
|
|
|
$this->stats = new Stats\Stats();
|
|
$this->helpers = new Helpers();
|
|
$this->pageSpeed = new PageSpeed();
|
|
$this->objects = new Objects();
|
|
$this->urlInspection = new UrlInspection();
|
|
$this->markers = new Markers();
|
|
$this->keywordRankTracker = new KeywordRankTracker();
|
|
$this->relatedKeywords = new RelatedKeywords();
|
|
$this->indexStatus = new IndexStatus();
|
|
}
|
|
|
|
/**
|
|
* Returns the data for Vue.
|
|
*
|
|
* @since 4.3.0
|
|
*
|
|
* @return array The data for Vue.
|
|
*/
|
|
public function getVueData() {
|
|
$dateRange = aioseo()->searchStatistics->stats->getDateRange();
|
|
|
|
$data = [
|
|
'latestAvailableDate' => aioseo()->searchStatistics->stats->latestAvailableDate,
|
|
'unverifiedSite' => aioseo()->searchStatistics->stats->unverifiedSite,
|
|
'rolling' => aioseo()->internalOptions->internal->searchStatistics->rolling,
|
|
'authedSite' => aioseo()->searchStatistics->api->auth->getAuthedSite(),
|
|
'quotaExceeded' => [
|
|
'urlInspection' => ! empty( aioseo()->core->cache->get( 'search_statistics_url_inspection_quota_exceeded' ) )
|
|
],
|
|
'data' => [
|
|
'seoStatistics' => $this->getSeoOverviewData( $dateRange ),
|
|
'keywords' => [],
|
|
'contentRankings' => $this->getContentRankingsData( $dateRange )
|
|
]
|
|
];
|
|
|
|
try {
|
|
$data['data']['keywords'] = $this->getKeywordsData( [
|
|
'startDate' => $dateRange['start'],
|
|
'endDate' => $dateRange['end']
|
|
] );
|
|
} catch ( \Exception $e ) {
|
|
// Do nothing.
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Resets the Search Statistics.
|
|
*
|
|
* @since 4.6.2
|
|
*
|
|
* @return void
|
|
*/
|
|
public function reset() {
|
|
parent::reset();
|
|
|
|
// Resets the results for the URL Inspection.
|
|
aioseo()->searchStatistics->urlInspection->reset();
|
|
}
|
|
|
|
/**
|
|
* Returns the SEO Overview data.
|
|
*
|
|
* @since 4.3.0
|
|
*
|
|
* @param array $dateRange The date range.
|
|
* @return array The SEO Overview data.
|
|
*/
|
|
protected function getSeoOverviewData( $dateRange = [] ) {
|
|
if (
|
|
! aioseo()->license->hasCoreFeature( 'search-statistics', 'seo-statistics' ) ||
|
|
! aioseo()->searchStatistics->api->auth->isConnected()
|
|
) {
|
|
return parent::getSeoOverviewData( $dateRange );
|
|
}
|
|
|
|
$cacheArgs = [
|
|
aioseo()->searchStatistics->api->auth->getAuthedSite(),
|
|
$dateRange['start'],
|
|
$dateRange['end'],
|
|
aioseo()->settings->tablePagination['searchStatisticsSeoStatistics'],
|
|
'0',
|
|
'all',
|
|
'',
|
|
'DESC',
|
|
'clicks',
|
|
''
|
|
];
|
|
|
|
$cacheHash = sha1( implode( ',', $cacheArgs ) );
|
|
$cachedData = aioseo()->core->cache->get( "aioseo_search_statistics_seo_statistics_{$cacheHash}" );
|
|
if ( $cachedData && ! empty( $cachedData['pages']['paginated']['rows'] ) ) {
|
|
$cachedData = aioseo()->searchStatistics->stats->posts->addPostData( $cachedData, 'statistics' );
|
|
$cachedData = aioseo()->searchStatistics->markers->addTimelineMarkers( $cachedData );
|
|
|
|
$cachedData['pages']['paginated']['filters'] = aioseo()->searchStatistics->stats->posts->getFilters( 'all', '' );
|
|
$cachedData['pages']['paginated']['additionalFilters'] = aioseo()->searchStatistics->stats->posts->getAdditionalFilters();
|
|
}
|
|
|
|
return $cachedData ?? [];
|
|
}
|
|
|
|
/**
|
|
* Returns the Keywords data.
|
|
*
|
|
* @since 4.3.0
|
|
* @version 4.7.2 Added the $args parameter.
|
|
*
|
|
* @param array $args The arguments.
|
|
* @throws \Exception
|
|
* @return array The Keywords data.
|
|
*/
|
|
public function getKeywordsData( $args = [] ) {
|
|
if (
|
|
! aioseo()->license->hasCoreFeature( 'search-statistics', 'keyword-rankings' ) ||
|
|
! aioseo()->searchStatistics->api->auth->isConnected()
|
|
) {
|
|
return parent::getKeywordsData();
|
|
}
|
|
|
|
$startDate = ! empty( $args['startDate'] ) ? $args['startDate'] : '';
|
|
$endDate = ! empty( $args['endDate'] ) ? $args['endDate'] : '';
|
|
$rolling = ! empty( $args['rolling'] ) ? $args['rolling'] : '';
|
|
$limit = ! empty( $args['limit'] ) ? $args['limit'] : aioseo()->settings->tablePagination['searchStatisticsKeywordRankings'];
|
|
$offset = ! empty( $args['offset'] ) ? $args['offset'] : 0;
|
|
$filter = ! empty( $args['filter'] ) ? $args['filter'] : 'all';
|
|
$searchTerm = ! empty( $args['searchTerm'] ) ? sanitize_text_field( $args['searchTerm'] ) : '';
|
|
$orderDir = ! empty( $args['orderDir'] ) ? strtoupper( $args['orderDir'] ) : 'DESC';
|
|
$orderBy = ! empty( $args['orderBy'] ) ? aioseo()->helpers->toCamelCase( $args['orderBy'] ) : 'clicks';
|
|
|
|
// If we're on the Top Losing/Top Winning pages, then we need to override the default ORDER BY/ORDER DIR.
|
|
if ( 'all' !== $filter ) {
|
|
if ( 'topLosing' === $filter ) {
|
|
$orderBy = 'decay';
|
|
$orderDir = 'ASC';
|
|
} elseif ( 'topWinning' === $filter ) {
|
|
$orderBy = 'decay';
|
|
$orderDir = 'DESC';
|
|
}
|
|
}
|
|
|
|
if ( empty( $startDate ) || empty( $endDate ) ) {
|
|
throw new \Exception( 'Invalid date range.' );
|
|
}
|
|
|
|
// Set the date range and rolling value.
|
|
aioseo()->searchStatistics->stats->setDateRange( $startDate, $endDate );
|
|
if ( aioseo()->internalOptions->searchStatistics->rolling !== $rolling ) {
|
|
aioseo()->internalOptions->searchStatistics->rolling = $rolling;
|
|
}
|
|
|
|
$cacheArgs = [
|
|
aioseo()->searchStatistics->api->auth->getAuthedSite(),
|
|
$startDate,
|
|
$endDate,
|
|
$limit,
|
|
$offset,
|
|
$filter,
|
|
$searchTerm,
|
|
$orderDir,
|
|
$orderBy
|
|
];
|
|
|
|
$cacheHash = sha1( implode( ',', $cacheArgs ) );
|
|
$cachedData = aioseo()->core->cache->get( "aioseo_search_statistics_keywords_{$cacheHash}" );
|
|
if ( null !== $cachedData ) {
|
|
return [
|
|
'data' => $cachedData,
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
$args = [
|
|
'start' => $startDate,
|
|
'end' => $endDate,
|
|
'pagination' => [
|
|
'limit' => $limit,
|
|
'offset' => $offset,
|
|
'filter' => $filter,
|
|
'searchTerm' => $searchTerm,
|
|
'orderDir' => $orderDir,
|
|
'orderBy' => $orderBy
|
|
]
|
|
];
|
|
|
|
$api = new CommonSearchStatistics\Api\Request( 'google-search-console/statistics/keywords/', $args, 'POST' );
|
|
$response = $api->request();
|
|
if ( is_wp_error( $response ) || ! empty( $response['error'] ) || empty( $response['data'] ) ) {
|
|
aioseo()->core->cache->update( "aioseo_search_statistics_keywords_{$cacheHash}", false, 60 );
|
|
|
|
return [
|
|
'data' => false,
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
$data = $response['data'];
|
|
|
|
// Add localized filters to paginated data.
|
|
$data['paginated']['filters'] = aioseo()->searchStatistics->stats->keywords->getFilters( $filter, $searchTerm );
|
|
|
|
aioseo()->core->cache->update( "aioseo_search_statistics_keywords_{$cacheHash}", $data, MONTH_IN_SECONDS );
|
|
|
|
return [
|
|
'data' => $data,
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Returns the Content Rankings data.
|
|
*
|
|
* @since 4.3.6
|
|
* @version 4.7.2 Added the $args parameter.
|
|
*
|
|
* @param array $args The arguments.
|
|
* @return array The Content Rankings data.
|
|
*/
|
|
public function getContentRankingsData( $args = [] ) {
|
|
if (
|
|
! aioseo()->license->hasCoreFeature( 'search-statistics', 'content-rankings' ) ||
|
|
! aioseo()->searchStatistics->api->auth->isConnected()
|
|
) {
|
|
return parent::getContentRankingsData();
|
|
}
|
|
|
|
$limit = ! empty( $args['limit'] ) ? $args['limit'] : aioseo()->settings->tablePagination['searchStatisticsKeywordRankings'];
|
|
$offset = ! empty( $args['offset'] ) ? $args['offset'] : 0;
|
|
$searchTerm = ! empty( $args['searchTerm'] ) ? sanitize_text_field( $args['searchTerm'] ) : '';
|
|
$orderDir = ! empty( $args['orderDir'] ) ? strtoupper( $args['orderDir'] ) : 'ASC';
|
|
$orderBy = ! empty( $args['orderBy'] ) ? aioseo()->helpers->toCamelCase( $args['orderBy'] ) : 'decay';
|
|
$additionalFilters = ! empty( $args['additionalFilters'] ) ? $args['additionalFilters'] : [];
|
|
|
|
$endDate = ! empty( $args['endDate'] ) ? $args['endDate'] : aioseo()->searchStatistics->stats->latestAvailableDate; // We do last available date for the end date.
|
|
$startDate = date( 'Y-m-d', strtotime( $endDate . ' - 1 year' ) );
|
|
|
|
$postType = ! empty( $additionalFilters['postType'] ) ? $additionalFilters['postType'] : '';
|
|
|
|
$postData = [];
|
|
if ( $searchTerm || in_array( $orderBy, [ 'postTitle', 'lastUpdated' ], true ) ) {
|
|
$postData = aioseo()->searchStatistics->stats->posts->getPostData( [ 'searchTerm' => $searchTerm ] );
|
|
}
|
|
|
|
$cacheArgs = [
|
|
aioseo()->searchStatistics->api->auth->getAuthedSite(),
|
|
$startDate,
|
|
$endDate,
|
|
$limit,
|
|
$offset,
|
|
$searchTerm,
|
|
$postType,
|
|
$orderDir,
|
|
$orderBy
|
|
];
|
|
|
|
$cacheHash = sha1( implode( ',', $cacheArgs ) );
|
|
$cachedData = aioseo()->core->cache->get( "aioseo_search_statistics_cont_rankings_{$cacheHash}" );
|
|
if ( null !== $cachedData ) {
|
|
if ( false !== $cachedData && ! empty( $cachedData['paginated']['rows'] ) ) {
|
|
// Add post objects to rows.
|
|
$cachedData = aioseo()->searchStatistics->stats->posts->addPostData( $cachedData, 'contentRankings' );
|
|
|
|
$cachedData['paginated']['additionalFilters'] = aioseo()->searchStatistics->stats->posts->getAdditionalFilters();
|
|
}
|
|
|
|
return [
|
|
'data' => $cachedData,
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
$args = [
|
|
'start' => $startDate,
|
|
'end' => $endDate,
|
|
'pagination' => [
|
|
'limit' => $limit,
|
|
'offset' => $offset,
|
|
'searchTerm' => $searchTerm,
|
|
'orderDir' => $orderDir,
|
|
'orderBy' => $orderBy,
|
|
'postData' => $postData,
|
|
'objects' => aioseo()->searchStatistics->stats->posts->getPostObjectPaths( $postType )
|
|
]
|
|
];
|
|
|
|
$api = new CommonSearchStatistics\Api\Request( 'google-search-console/statistics/content-rankings/', $args, 'POST' );
|
|
$response = $api->request();
|
|
|
|
if ( is_wp_error( $response ) || ! empty( $response['error'] ) || empty( $response['data'] ) ) {
|
|
aioseo()->core->cache->update( "aioseo_search_statistics_cont_rankings_{$cacheHash}", false, 60 );
|
|
|
|
return [
|
|
'data' => false,
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
$data = $response['data'];
|
|
|
|
aioseo()->core->cache->update( "aioseo_search_statistics_cont_rankings_{$cacheHash}", $data, MONTH_IN_SECONDS );
|
|
|
|
// Add post objects to rows.
|
|
$data = aioseo()->searchStatistics->stats->posts->addPostData( $data, 'contentRankings' );
|
|
|
|
$data['paginated']['additionalFilters'] = aioseo()->searchStatistics->stats->posts->getAdditionalFilters();
|
|
|
|
return [
|
|
'data' => $data,
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Returns the content performance data.
|
|
*
|
|
* @since 4.7.2
|
|
*
|
|
* @param array $args The arguments.
|
|
* @throws \Exception
|
|
* @return array The content performance data.
|
|
*/
|
|
public function getSeoStatisticsData( $args = [] ) {
|
|
// Check if Search Statistics is connected
|
|
if ( ! aioseo()->searchStatistics->api->auth->isConnected() ) {
|
|
return [
|
|
'data' => false,
|
|
'error' => 'Search Statistics is not connected. Please connect your Google Search Console account.',
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
$startDate = ! empty( $args['startDate'] ) ? $args['startDate'] : '';
|
|
$endDate = ! empty( $args['endDate'] ) ? $args['endDate'] : '';
|
|
$rolling = ! empty( $args['rolling'] ) ? $args['rolling'] : '';
|
|
$limit = ! empty( $args['limit'] ) ? $args['limit'] : aioseo()->settings->tablePagination['searchStatisticsSeoStatistics'];
|
|
$offset = ! empty( $args['offset'] ) ? $args['offset'] : 0;
|
|
$filter = ! empty( $args['filter'] ) ? $args['filter'] : 'all';
|
|
$searchTerm = ! empty( $args['searchTerm'] ) ? sanitize_text_field( $args['searchTerm'] ) : '';
|
|
$orderDir = ! empty( $args['orderDir'] ) ? strtoupper( $args['orderDir'] ) : 'DESC';
|
|
$orderBy = ! empty( $args['orderBy'] ) ? aioseo()->helpers->toCamelCase( $args['orderBy'] ) : 'clicks';
|
|
$additionalFilters = ! empty( $args['additionalFilters'] ) ? $args['additionalFilters'] : [];
|
|
|
|
$postType = ! empty( $additionalFilters['postType'] ) ? $additionalFilters['postType'] : '';
|
|
|
|
// If we're on the Top Losing/Top Winning pages, then we need to override the default ORDER BY/ORDER DIR.
|
|
if ( 'all' !== $filter ) {
|
|
if ( 'topLosing' === $filter ) {
|
|
$orderBy = 'decay';
|
|
$orderDir = 'ASC';
|
|
} elseif ( 'topWinning' === $filter ) {
|
|
$orderBy = 'decay';
|
|
$orderDir = 'DESC';
|
|
}
|
|
}
|
|
|
|
if ( empty( $startDate ) || empty( $endDate ) ) {
|
|
throw new \Exception( 'Invalid date range.' );
|
|
}
|
|
|
|
$postData = [];
|
|
if ( $searchTerm || in_array( $orderBy, [ 'postTitle', 'lastUpdated' ], true ) ) {
|
|
$postData = aioseo()->searchStatistics->stats->posts->getPostData( [ 'searchTerm' => $searchTerm ] );
|
|
}
|
|
|
|
// Set the date range and rolling value.
|
|
aioseo()->searchStatistics->stats->setDateRange( $startDate, $endDate );
|
|
if ( aioseo()->internalOptions->searchStatistics->rolling !== $rolling ) {
|
|
aioseo()->internalOptions->searchStatistics->rolling = $rolling;
|
|
}
|
|
|
|
$cacheArgs = [
|
|
aioseo()->searchStatistics->api->auth->getAuthedSite(),
|
|
$startDate,
|
|
$endDate,
|
|
$limit,
|
|
$offset,
|
|
$filter,
|
|
$searchTerm,
|
|
$orderDir,
|
|
$orderBy,
|
|
$postType
|
|
];
|
|
|
|
$cacheHash = sha1( implode( ',', $cacheArgs ) );
|
|
$cachedData = aioseo()->core->cache->get( "aioseo_search_statistics_seo_statistics_{$cacheHash}" );
|
|
if ( null !== $cachedData ) {
|
|
if ( false !== $cachedData && ! empty( $cachedData['pages'] ) ) {
|
|
// Add post objects to rows.
|
|
$cachedData = aioseo()->searchStatistics->stats->posts->addPostData( $cachedData, 'statistics' );
|
|
|
|
// Add graph markers.
|
|
$cachedData = aioseo()->searchStatistics->markers->addTimelineMarkers( $cachedData );
|
|
|
|
// Add localized filters to paginated data.
|
|
$cachedData['pages']['paginated']['filters'] = aioseo()->searchStatistics->stats->posts->getFilters( $filter, $searchTerm );
|
|
$cachedData['pages']['paginated']['additionalFilters'] = aioseo()->searchStatistics->stats->posts->getAdditionalFilters();
|
|
}
|
|
|
|
return [
|
|
'data' => $cachedData,
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
$args = [
|
|
'start' => $startDate,
|
|
'end' => $endDate,
|
|
'pagination' => [
|
|
'limit' => $limit,
|
|
'offset' => $offset,
|
|
'filter' => $filter,
|
|
'searchTerm' => $searchTerm,
|
|
'orderDir' => $orderDir,
|
|
'orderBy' => $orderBy,
|
|
'postData' => $postData,
|
|
'objects' => ! empty( $postType ) ? aioseo()->searchStatistics->stats->posts->getPostObjectPaths( $postType ) : false
|
|
]
|
|
];
|
|
|
|
// Log request details for debugging
|
|
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
|
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
|
|
error_log( sprintf(
|
|
"[AIOSEO Search Statistics] Making API request\nEndpoint: google-search-console/statistics/\nRequest Args: %s\nIs Connected: %s\nAuthed Site: %s",
|
|
wp_json_encode( $args, JSON_PRETTY_PRINT ),
|
|
aioseo()->searchStatistics->api->auth->isConnected() ? 'Yes' : 'No',
|
|
aioseo()->searchStatistics->api->auth->getAuthedSite() ?: 'None'
|
|
) );
|
|
}
|
|
|
|
$api = new CommonSearchStatistics\Api\Request( 'google-search-console/statistics/', $args, 'POST' );
|
|
$response = $api->request();
|
|
if ( is_wp_error( $response ) || ! empty( $response['error'] ) || empty( $response['data'] ) ) {
|
|
aioseo()->core->cache->update( "aioseo_search_statistics_seo_statistics_{$cacheHash}", false, 60 );
|
|
|
|
// Log detailed error information for debugging
|
|
$errorMessage = '';
|
|
$errorCode = '';
|
|
$errorDetails = [];
|
|
|
|
if ( is_wp_error( $response ) ) {
|
|
$errorMessage = $response->get_error_message();
|
|
$errorCode = $response->get_error_code();
|
|
$errorData = $response->get_error_data();
|
|
if ( $errorData ) {
|
|
$errorDetails['error_data'] = $errorData;
|
|
}
|
|
} elseif ( ! empty( $response ) && is_array( $response ) ) {
|
|
// Check for error field first
|
|
if ( ! empty( $response['error'] ) ) {
|
|
if ( is_string( $response['error'] ) ) {
|
|
$errorMessage = $response['error'];
|
|
} elseif ( is_array( $response['error'] ) ) {
|
|
$errorDetails['error_array'] = $response['error'];
|
|
// Try to extract message from error array
|
|
if ( isset( $response['error']['message'] ) ) {
|
|
$errorMessage = $response['error']['message'];
|
|
} elseif ( isset( $response['error'][0] ) && is_string( $response['error'][0] ) ) {
|
|
$errorMessage = $response['error'][0];
|
|
} else {
|
|
$errorMessage = 'API returned error array: ' . wp_json_encode( $response['error'] );
|
|
}
|
|
}
|
|
}
|
|
// Check for message field
|
|
if ( empty( $errorMessage ) && ! empty( $response['message'] ) ) {
|
|
$errorMessage = $response['message'];
|
|
}
|
|
// Check for status field
|
|
if ( ! empty( $response['status'] ) ) {
|
|
$errorCode = $response['status'];
|
|
}
|
|
// If still no error message but data is empty
|
|
if ( empty( $errorMessage ) && empty( $response['data'] ) ) {
|
|
$errorMessage = 'API response contains no data';
|
|
}
|
|
} else {
|
|
$errorMessage = 'Invalid API response format';
|
|
}
|
|
|
|
// Build comprehensive error details
|
|
$errorDetails['request_args'] = [
|
|
'startDate' => $startDate,
|
|
'endDate' => $endDate,
|
|
'filter' => $filter,
|
|
'limit' => $limit,
|
|
'offset' => $offset
|
|
];
|
|
$errorDetails['is_connected'] = aioseo()->searchStatistics->api->auth->isConnected();
|
|
$errorDetails['authed_site'] = aioseo()->searchStatistics->api->auth->getAuthedSite();
|
|
if ( ! empty( $response ) && is_array( $response ) ) {
|
|
$errorDetails['response_keys'] = array_keys( $response );
|
|
// Capture all response fields for debugging
|
|
if ( isset( $response['error'] ) ) {
|
|
$errorDetails['response_error'] = $response['error'];
|
|
}
|
|
if ( isset( $response['status'] ) ) {
|
|
$errorDetails['response_status'] = $response['status'];
|
|
}
|
|
if ( isset( $response['message'] ) ) {
|
|
$errorDetails['response_message'] = $response['message'];
|
|
}
|
|
if ( isset( $response['data'] ) ) {
|
|
$errorDetails['response_data_type'] = gettype( $response['data'] );
|
|
$errorDetails['response_data_empty'] = empty( $response['data'] );
|
|
}
|
|
if ( isset( $response['response'] ) ) {
|
|
$errorDetails['http_response'] = $response['response'];
|
|
}
|
|
// Log full response for debugging (but limit size)
|
|
$errorDetails['full_response'] = $response;
|
|
}
|
|
|
|
// Log to WordPress debug log
|
|
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
|
$logMessage = sprintf(
|
|
"[AIOSEO Search Statistics] API Error: %s\nError Code: %s\nRequest Args: %s\nIs Connected: %s\nAuthed Site: %s\nFull Error Details: %s",
|
|
$errorMessage ?: 'Unknown error',
|
|
$errorCode ?: 'N/A',
|
|
wp_json_encode( $errorDetails['request_args'] ),
|
|
$errorDetails['is_connected'] ? 'Yes' : 'No',
|
|
$errorDetails['authed_site'] ?: 'None',
|
|
wp_json_encode( $errorDetails, JSON_PRETTY_PRINT )
|
|
);
|
|
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
|
|
error_log( $logMessage );
|
|
}
|
|
|
|
return [
|
|
'data' => false,
|
|
'error' => $errorMessage,
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
$data = $response['data'];
|
|
aioseo()->core->cache->update( "aioseo_search_statistics_seo_statistics_{$cacheHash}", $data, MONTH_IN_SECONDS );
|
|
|
|
// Add post objects to rows.
|
|
$data = aioseo()->searchStatistics->stats->posts->addPostData( $data, 'statistics' );
|
|
|
|
// Add graph markers.
|
|
$data = aioseo()->searchStatistics->markers->addTimelineMarkers( $data );
|
|
|
|
// Add localized filters to paginated data.
|
|
$data['pages']['paginated']['filters'] = aioseo()->searchStatistics->stats->posts->getFilters( $filter, $searchTerm );
|
|
$data['pages']['paginated']['additionalFilters'] = aioseo()->searchStatistics->stats->posts->getAdditionalFilters();
|
|
|
|
return [
|
|
'data' => $data,
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Returns the post detail SEO statistics data.
|
|
*
|
|
* @since 4.7.2
|
|
*
|
|
* @param array $args The arguments.
|
|
* @throws \Exception
|
|
* @return array The post detail SEO statistics data.
|
|
*/
|
|
public function getPostDetailSeoStatisticsData( $args = [], $markers = true ) {
|
|
if ( ! aioseo()->license->hasCoreFeature( 'search-statistics', 'post-detail-seo-statistics' ) ) {
|
|
return parent::getContentRankingsData();
|
|
}
|
|
|
|
$startDate = ! empty( $args['startDate'] ) ? $args['startDate'] : '';
|
|
$endDate = ! empty( $args['endDate'] ) ? $args['endDate'] : '';
|
|
$postId = ! empty( $args['postId'] ) ? $args['postId'] : '';
|
|
|
|
if ( empty( $startDate ) || empty( $endDate ) ) {
|
|
throw new \Exception( 'Invalid date range.' );
|
|
}
|
|
|
|
if ( empty( $postId ) || ! is_numeric( $postId ) ) {
|
|
throw new \Exception( 'Invalid post id.' );
|
|
}
|
|
|
|
aioseo()->searchStatistics->stats->setDateRange( $startDate, $endDate );
|
|
|
|
$permalink = get_permalink( $postId );
|
|
$page = aioseo()->searchStatistics->helpers->getPageSlug( $permalink );
|
|
|
|
$baseUrl = untrailingslashit( aioseo()->searchStatistics->api->auth->getAuthedSite() );
|
|
$pageUrl = $baseUrl . $page;
|
|
$args = [
|
|
'start' => $startDate,
|
|
'end' => $endDate,
|
|
'page' => $pageUrl
|
|
];
|
|
|
|
$cacheArgs = [
|
|
$startDate,
|
|
$endDate,
|
|
$pageUrl
|
|
];
|
|
|
|
$cacheHash = sha1( implode( ',', $cacheArgs ) );
|
|
$cachedData = aioseo()->core->cache->get( "aioseo_search_statistics_page_stats_{$cacheHash}" );
|
|
if ( null !== $cachedData ) {
|
|
if ( false !== $cachedData && $markers ) {
|
|
// Add graph markers.
|
|
$cachedData = aioseo()->searchStatistics->markers->addTimelineMarkers( $cachedData, $postId );
|
|
}
|
|
|
|
return [
|
|
'data' => $cachedData,
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
$api = new CommonSearchStatistics\Api\Request( 'google-search-console/statistics/page/', $args, 'POST' );
|
|
$response = $api->request();
|
|
if ( is_wp_error( $response ) || ! empty( $response['error'] ) || empty( $response['data'] ) ) {
|
|
aioseo()->core->cache->update( "aioseo_search_statistics_page_stats_{$cacheHash}", false, 60 );
|
|
|
|
return [
|
|
'data' => false,
|
|
'range' => aioseo()->searchStatistics->stats->getDateRange()
|
|
];
|
|
}
|
|
|
|
$data = $response['data'];
|
|
aioseo()->core->cache->update( "aioseo_search_statistics_page_stats_{$cacheHash}", $response['data'], MONTH_IN_SECONDS );
|
|
|
|
if ( $markers ) {
|
|
// Add graph markers.
|
|
$data = aioseo()->searchStatistics->markers->addTimelineMarkers( $data, $postId );
|
|
}
|
|
|
|
return [
|
|
'data' => $data,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Returns all scheduled Search Statistics related actions.
|
|
*
|
|
* @since 4.6.2
|
|
*
|
|
* @return array The Search Statistics actions.
|
|
*/
|
|
protected function getActionSchedulerActions() {
|
|
return array_merge(
|
|
parent::getActionSchedulerActions(),
|
|
[
|
|
$this->objects->action,
|
|
$this->stats->latestAvailableDateAction
|
|
]
|
|
);
|
|
}
|
|
} |