| Current Path : /home/x/b/o/xbodynamge/namtation/wp-content/ |
| Current File : /home/x/b/o/xbodynamge/namtation/wp-content/Summary.tar |
Content.php 0000666 00000050371 15114441267 0006706 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\EmailReports\Summary;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* Summary content class.
*
* @since 4.7.2
*/
class Content {
/**
* The date range data.
*
* @since 4.7.2
*
* @var array
*/
public $dateRange;
/**
* The SEO Statistics data.
*
* @since 4.7.2
*
* @var array
*/
private $seoStatistics = [];
/**
* The Keywords data.
*
* @since 4.7.2
*
* @var array
*/
private $keywords = [];
/**
* The Search Statistics page URL.
*
* @since 4.7.2
*
* @var string
*/
public $searchStatisticsUrl;
/**
* The featured image placeholder URL.
*
* @since 4.7.3
*
* @var string
*/
public $featuredImagePlaceholder = 'https://static.aioseo.io/report/ste/featured-image-placeholder.png';
/**
* Class constructor.
*
* @since 4.7.2
*
* @param array $dateRange The date range data.
* @return void
*/
public function __construct( $dateRange ) {
$this->dateRange = $dateRange;
$this->searchStatisticsUrl = admin_url( 'admin.php?page=aioseo-search-statistics' );
$this->setSeoStatistics();
$this->setKeywords();
}
/**
* Sets the SEO Statistics data.
*
* @since 4.7.2
*
* @return void
*/
private function setSeoStatistics() {
try {
$seoStatistics = aioseo()->searchStatistics->getSeoStatisticsData( [
'startDate' => gmdate( 'Y-m-d', $this->dateRange['startDateRaw'] ),
'endDate' => gmdate( 'Y-m-d', $this->dateRange['endDateRaw'] ),
'orderBy' => 'clicks',
'orderDir' => 'desc',
'limit' => '5',
'offset' => '0',
'filter' => 'all',
] );
if ( empty( $seoStatistics['data'] ) ) {
return;
}
$this->seoStatistics = $seoStatistics['data'];
} catch ( \Exception $e ) {
// Do nothing.
}
}
/**
* Sets the Keywords data.
*
* @since 4.7.2
*
* @return void
*/
private function setKeywords() {
try {
$keywords = aioseo()->searchStatistics->getKeywordsData( [
'startDate' => gmdate( 'Y-m-d', $this->dateRange['startDateRaw'] ),
'endDate' => gmdate( 'Y-m-d', $this->dateRange['endDateRaw'] ),
'orderBy' => 'clicks',
'orderDir' => 'desc',
'limit' => '5',
'offset' => '0',
'filter' => 'all',
] );
if ( empty( $keywords['data'] ) ) {
return;
}
$this->keywords = $keywords['data'];
} catch ( \Exception $e ) {
// Do nothing.
}
}
/**
* Retrieves the content performance data.
*
* @since 4.7.2
*
* @return array The content performance data or an empty array.
*/
public function getPostsStatistics() {
if ( ! $this->seoStatistics ) {
return [];
}
$result = [
'winning' => [
'url' => add_query_arg( [
'aioseo-scroll' => 'aioseo-search-statistics-post-table',
'aioseo-tab' => 'seo-statistics',
'table-filter' => 'TopWinningPages'
], $this->searchStatisticsUrl ),
'items' => []
],
'losing' => [
'url' => add_query_arg( [
'aioseo-scroll' => 'aioseo-search-statistics-post-table',
'aioseo-tab' => 'seo-statistics',
'table-filter' => 'TopLosingPages'
], $this->searchStatisticsUrl ),
'items' => []
]
];
foreach ( array_slice( $this->seoStatistics['pages']['topWinning']['rows'], 0, 3 ) as $row ) {
$postId = $row['objectId'] ?? 0;
$result['winning']['items'][] = [
'title' => $row['objectTitle'],
'url' => get_permalink( $postId ),
'tru_seo' => aioseo()->helpers->isTruSeoEligible( $postId ) ? $this->parseSeoScore( $row['seoScore'] ?? 0 ) : [],
'clicks' => $this->parseClicks( $row['clicks'] ),
'difference' => [
'clicks' => $this->parseDifference( $row['difference']['clicks'] ?? '' ),
]
];
}
$result['winning']['show_tru_seo'] = ! empty( array_filter( array_column( $result['winning']['items'], 'tru_seo' ) ) );
foreach ( array_slice( $this->seoStatistics['pages']['topLosing']['rows'], 0, 3 ) as $row ) {
$postId = $row['objectId'] ?? 0;
$result['losing']['items'][] = [
'title' => $row['objectTitle'],
'url' => get_permalink( $postId ),
'tru_seo' => aioseo()->helpers->isTruSeoEligible( $postId ) ? $this->parseSeoScore( $row['seoScore'] ?? 0 ) : [],
'clicks' => $this->parseClicks( $row['clicks'] ),
'difference' => [
'clicks' => $this->parseDifference( $row['difference']['clicks'] ?? '' ),
]
];
}
$result['losing']['show_tru_seo'] = ! empty( array_filter( array_column( $result['losing']['items'], 'tru_seo' ) ) );
return $result;
}
/**
* Retrieves the milestones data.
*
* @since 4.7.2
*
* @return array The milestones data or an empty array.
*/
public function getMilestones() { // phpcs:ignore Generic.Files.LineLength.MaxExceeded
$milestones = [];
if ( ! $this->seoStatistics ) {
return $milestones;
}
$currentData = [
'impressions' => $this->seoStatistics['statistics']['impressions'] ?? null,
'clicks' => $this->seoStatistics['statistics']['clicks'] ?? null,
'ctr' => $this->seoStatistics['statistics']['ctr'] ?? null,
'keywords' => $this->seoStatistics['statistics']['keywords'] ?? null,
];
$difference = [
'impressions' => $this->seoStatistics['statistics']['difference']['impressions'] ?? null,
'clicks' => $this->seoStatistics['statistics']['difference']['clicks'] ?? null,
'ctr' => $this->seoStatistics['statistics']['difference']['ctr'] ?? null,
'keywords' => $this->seoStatistics['statistics']['difference']['keywords'] ?? null,
];
if ( is_numeric( $currentData['impressions'] ) && is_numeric( $difference['impressions'] ) ) {
$intDifference = intval( $difference['impressions'] );
$message = esc_html__( 'Your site has received the same number of impressions compared to the previous period.', 'all-in-one-seo-pack' );
if ( $intDifference > 0 ) {
// Translators: 1 - The number of impressions, 2 - The percentage increase.
$message = esc_html__( 'Your site has received %1$s more impressions compared to the previous period, which is a %2$s increase.', 'all-in-one-seo-pack' );
}
if ( $intDifference < 0 ) {
// Translators: 1 - The number of impressions, 2 - The percentage increase.
$message = esc_html__( 'Your site has received %1$s fewer impressions compared to the previous period, which is a %2$s decrease.', 'all-in-one-seo-pack' );
}
if ( false !== strpos( $message, '%1' ) ) {
$percentageDiff = 0 === absint( $currentData['impressions'] )
? 100
: round( ( absint( $intDifference ) / absint( $currentData['impressions'] ) ) * 100, 2 );
$percentageDiff = false !== strpos( $percentageDiff, '.' )
? number_format_i18n( $percentageDiff, count( explode( '.', $percentageDiff ) ) )
: $percentageDiff;
$message = sprintf(
$message,
'<strong>' . aioseo()->helpers->compactNumber( absint( $intDifference ) ) . '</strong>',
'<strong>' . $percentageDiff . '%</strong>'
);
}
$milestones[] = [
'message' => $message,
'background' => '#f0f6ff',
'color' => '#004F9D',
'icon' => 'icon-milestone-impressions'
];
}
if ( is_numeric( $currentData['clicks'] ) && is_numeric( $difference['clicks'] ) ) {
$intDifference = intval( $difference['clicks'] );
$message = esc_html__( 'Your site has received the same number of clicks compared to the previous period.', 'all-in-one-seo-pack' );
if ( $intDifference > 0 ) {
// Translators: 1 - The number of clicks, 2 - The percentage increase.
$message = esc_html__( 'Your site has received %1$s more clicks compared to the previous period, which is a %2$s increase.', 'all-in-one-seo-pack' );
}
if ( $intDifference < 0 ) {
// Translators: 1 - The number of clicks, 2 - The percentage increase.
$message = esc_html__( 'Your site has received %1$s fewer clicks compared to the previous period, which is a %2$s decrease.', 'all-in-one-seo-pack' );
}
if ( false !== strpos( $message, '%1' ) ) {
$percentageDiff = 0 === absint( $currentData['clicks'] )
? 100
: round( ( absint( $intDifference ) / absint( $currentData['clicks'] ) ) * 100, 2 );
$percentageDiff = false !== strpos( $percentageDiff, '.' )
? number_format_i18n( $percentageDiff, count( explode( '.', $percentageDiff ) ) )
: $percentageDiff;
$message = sprintf(
$message,
'<strong>' . aioseo()->helpers->compactNumber( absint( $intDifference ) ) . '</strong>',
'<strong>' . $percentageDiff . '%</strong>'
);
}
$milestones[] = [
'message' => $message,
'background' => '#ecfdf5',
'color' => '#077647',
'icon' => 'icon-milestone-clicks'
];
}
if ( is_numeric( $currentData['ctr'] ) && is_numeric( $difference['ctr'] ) ) {
$intDifference = floatval( $difference['ctr'] );
$message = esc_html__( 'Your site has the same CTR compared to the previous period.', 'all-in-one-seo-pack' );
if ( $intDifference > 0 ) {
// Translators: 1 - The CTR.
$message = esc_html__( 'Your site has a %1$s higher CTR compared to the previous period.', 'all-in-one-seo-pack' );
}
if ( $intDifference < 0 ) {
// Translators: 1 - The CTR.
$message = esc_html__( 'Your site has a %1$s lower CTR compared to the previous period.', 'all-in-one-seo-pack' );
}
if ( false !== strpos( $message, '%1' ) ) {
$message = sprintf(
$message,
'<strong>' . number_format_i18n( abs( $intDifference ), count( explode( '.', $intDifference ) ) ) . '%</strong>'
);
}
$milestones[] = [
'message' => $message,
'background' => '#fffbeb',
'color' => '#be6903',
'icon' => 'icon-milestone-ctr'
];
}
if ( is_numeric( $currentData['keywords'] ) && is_numeric( $difference['keywords'] ) ) {
$intDifference = intval( $difference['keywords'] );
$message = esc_html__( 'Your site ranked for the same number of keywords compared to the previous period.', 'all-in-one-seo-pack' );
if ( $intDifference > 0 ) {
// Translators: 1 - The number of keywords, 2 - The percentage increase.
$message = esc_html__( 'Your site ranked for %1$s more keywords compared to the previous period, which is a %2$s increase.', 'all-in-one-seo-pack' );
}
if ( $intDifference < 0 ) {
// Translators: 1 - The number of keywords, 2 - The percentage increase.
$message = esc_html__( 'Your site ranked for %1$s fewer keywords compared to the previous period, which is a %2$s decrease.', 'all-in-one-seo-pack' );
}
if ( false !== strpos( $message, '%1' ) ) {
$percentageDiff = 0 === absint( $currentData['keywords'] )
? 100
: round( ( absint( $intDifference ) / absint( $currentData['keywords'] ) ) * 100, 2 );
$percentageDiff = false !== strpos( $percentageDiff, '.' )
? number_format_i18n( $percentageDiff, count( explode( '.', $percentageDiff ) ) )
: $percentageDiff;
$message = sprintf(
$message,
'<strong>' . aioseo()->helpers->compactNumber( absint( $intDifference ) ) . '</strong>',
'<strong>' . $percentageDiff . '%</strong>'
);
}
$milestones[] = [
'message' => $message,
'background' => '#fef2f2',
'color' => '#ab2039',
'icon' => 'icon-milestone-keywords'
];
}
return $milestones;
}
/**
* Retrieves the keyword performance data.
*
* @since 4.7.2
*
* @return array The keyword performance data or an empty array.
*/
public function getKeywords() {
if ( ! $this->keywords ) {
return [];
}
$result = [
'winning' => [
'url' => add_query_arg( [
'aioseo-scroll' => 'aioseo-search-statistics-keywords-table',
'aioseo-tab' => 'keyword-rank-tracker',
'tab' => 'AllKeywords',
'table-filter' => 'TopWinningKeywords'
], $this->searchStatisticsUrl ),
'items' => []
],
'losing' => [
'url' => add_query_arg( [
'aioseo-scroll' => 'aioseo-search-statistics-keywords-table',
'aioseo-tab' => 'keyword-rank-tracker',
'tab' => 'AllKeywords',
'table-filter' => 'TopLosingKeywords'
], $this->searchStatisticsUrl ),
'items' => []
]
];
foreach ( array_slice( $this->keywords['topWinning'], 0, 3 ) as $row ) {
$result['winning']['items'][] = [
'title' => $row['keyword'],
'clicks' => $this->parseClicks( $row['clicks'] ),
'difference' => [
'clicks' => $this->parseDifference( $row['difference']['clicks'] ?? '' ),
]
];
}
foreach ( array_slice( $this->keywords['topLosing'], 0, 3 ) as $row ) {
$result['losing']['items'][] = [
'title' => $row['keyword'],
'clicks' => $this->parseClicks( $row['clicks'] ),
'difference' => [
'clicks' => $this->parseDifference( $row['difference']['clicks'] ?? '' ),
]
];
}
return $result;
}
/**
* Retrieves the posts data.
*
* @since 4.7.2
*
* @return array The posts' data.
*/
public function getAioPosts() {
$result = [
'publish' => [],
'optimize' => [],
'cta' => [
'text' => esc_html__( 'Create New Post', 'all-in-one-seo-pack' ),
'url' => admin_url( 'post-new.php' )
],
];
// 1. Retrieve the published posts.
$publishPosts = aioseo()->core->db
->start( 'posts as wp' )
->select( 'wp.ID, wp.post_title, aio.seo_score' )
->join( 'aioseo_posts as aio', 'aio.post_id = wp.ID', 'INNER' )
->whereIn( 'wp.post_type', [ 'post' ] )
->whereIn( 'wp.post_status', [ 'publish' ] )
->orderBy( 'wp.post_date DESC' )
->limit( 5 )
->run()
->result();
if ( $publishPosts ) {
$items = $this->parsePosts( $publishPosts );
$result['publish'] = [
'url' => admin_url( 'edit.php?post_status=publish&post_type=post' ),
'items' => $items,
'show_stats' => ! empty( array_filter( array_column( $items, 'stats' ) ) ),
'show_tru_seo' => ! empty( array_filter( array_column( $items, 'tru_seo' ) ) ),
];
}
// 2. Retrieve the posts to optimize.
$optimizePosts = aioseo()->searchStatistics->getContentRankingsData( [
'endDate' => gmdate( 'Y-m-d', $this->dateRange['endDateRaw'] ),
'orderBy' => 'decayPercent',
'orderDir' => 'asc',
'limit' => '3',
'offset' => '0',
'filter' => 'all',
] );
if ( is_array( $optimizePosts['data']['paginated']['rows'] ?? '' ) ) {
$items = [];
foreach ( array_slice( $optimizePosts['data']['paginated']['rows'], 0, 3 ) as $i => $row ) {
$postId = $row['objectId'] ?? 0;
$items[ $i ] = [
'title' => $row['objectTitle'],
'url' => get_permalink( $postId ),
'image_url' => $this->getThumbnailUrl( $postId ),
'tru_seo' => aioseo()->helpers->isTruSeoEligible( $postId ) ? $this->parseSeoScore( $row['seoScore'] ?? 0 ) : [],
'decay_percent' => $this->parseDifference( $row['decayPercent'] ?? '', true ),
'issues' => [
'url' => add_query_arg( [
'aioseo-tab' => 'post-detail',
'post' => $postId
], $this->searchStatisticsUrl ),
'items' => []
]
];
$aioPost = Models\Post::getPost( $postId );
if ( $aioPost ) {
$items[ $i ]['issues']['items'] = aioseo()->searchStatistics->helpers->getSuggestedChanges( $aioPost );
}
}
$result['optimize'] = [
'url' => add_query_arg( [
'aioseo-tab' => 'content-rankings',
], $this->searchStatisticsUrl ),
'items' => $items,
'show_tru_seo' => ! empty( array_filter( array_column( $items, 'tru_seo' ) ) ),
];
}
return $result;
}
/**
* Retrieves the resources data.
*
* @since 4.7.2
*
* @return array The resources' data.
*/
public function getResources() {
$items = aioseo()->helpers->fetchAioseoArticles( true );
return array_slice( array_filter( $items ), 0, 3 );
}
/**
* Returns if Search Statistics content is allowed.
*
* @since 4.7.3
*
* @return bool Whether Search Statistics content is allowed.
*/
public function allowSearchStatistics() {
static $return = null;
if ( isset( $return ) ) {
return $return;
}
$return = aioseo()->searchStatistics->api->auth->isConnected() &&
aioseo()->license &&
aioseo()->license->hasCoreFeature( 'search-statistics', 'seo-statistics' ) &&
aioseo()->license->hasCoreFeature( 'search-statistics', 'keyword-rankings' );
return $return;
}
/**
* Parses the SEO score.
*
* @since 4.7.2
*
* @param int|string $score The SEO score.
* @return array The parsed SEO score.
*/
private function parseSeoScore( $score ) {
$score = intval( $score );
$parsed = [
'value' => $score,
'color' => '#a1a1a1',
'text' => $score ? "$score/100" : esc_html__( 'N/A', 'all-in-one-seo-pack' ),
];
if ( $parsed['value'] > 79 ) {
$parsed['color'] = '#00aa63';
} elseif ( $parsed['value'] > 49 ) {
$parsed['color'] = '#ff8c00';
} elseif ( $parsed['value'] > 0 ) {
$parsed['color'] = '#df2a4a';
}
return $parsed;
}
/**
* Parses a difference.
*
* @since 4.7.2
*
* @param int|string $number The number to parse.
* @param bool $percentage Whether to return the text result as a percentage.
* @return array The parsed result.
*/
private function parseDifference( $number, $percentage = false ) {
$parsed = [
'color' => '#a1a1a1',
'text' => esc_html__( 'N/A', 'all-in-one-seo-pack' ),
];
if ( ! is_numeric( $number ) ) {
return $parsed;
}
$number = intval( $number );
$parsed['text'] = aioseo()->helpers->compactNumber( absint( $number ) );
if ( $percentage ) {
$parsed['text'] = $number . '%';
}
if ( $number > 0 ) {
$parsed['color'] = '#00aa63';
} elseif ( $number < 0 ) {
$parsed['color'] = '#df2a4a';
}
return $parsed;
}
/**
* Parses the clicks number.
*
* @since 4.7.2
*
* @param float|int|string $number The number of clicks.
* @return string The parsed number of clicks.
*/
private function parseClicks( $number ) {
return aioseo()->helpers->compactNumber( $number );
}
/**
* Parses the posts data.
*
* @since 4.7.2
*
* @param array $posts The posts.
* @return array The parsed posts' data.
*/
private function parsePosts( $posts ) {
$parsed = [];
foreach ( $posts as $k => $item ) {
$parsed[ $k ] = [
'title' => aioseo()->helpers->truncate( $item->post_title, 75 ),
'url' => get_permalink( $item->ID ),
'image_url' => $this->getThumbnailUrl( $item->ID ),
'tru_seo' => aioseo()->helpers->isTruSeoEligible( $item->ID ) ? $this->parseSeoScore( $item->seo_score ?? 0 ) : [],
'stats' => []
];
try {
$statistics = [];
if (
$this->allowSearchStatistics() &&
method_exists( aioseo()->searchStatistics, 'getPostDetailSeoStatisticsData' )
) {
$statistics = aioseo()->searchStatistics->getPostDetailSeoStatisticsData( [
'startDate' => gmdate( 'Y-m-d', $this->dateRange['startDateRaw'] ),
'endDate' => gmdate( 'Y-m-d', $this->dateRange['endDateRaw'] ),
'postId' => $item->ID,
], false );
}
if ( isset( $statistics['data']['statistics']['position'] ) ) {
$parsed[ $k ]['stats'][] = [
'icon' => 'position',
'label' => esc_html__( 'Position', 'all-in-one-seo-pack' ),
'value' => round( floatval( $statistics['data']['statistics']['position'] ) ),
];
}
if ( isset( $statistics['data']['statistics']['ctr'] ) ) {
$value = round( floatval( $statistics['data']['statistics']['ctr'] ), 2 );
$parsed[ $k ]['stats'][] = [
'icon' => 'ctr',
'label' => 'CTR',
'value' => ( number_format_i18n( $value, count( explode( '.', $value ) ) ) ) . '%',
];
}
if ( isset( $statistics['data']['statistics']['impressions'] ) ) {
$parsed[ $k ]['stats'][] = [
'icon' => 'impressions',
'label' => esc_html__( 'Impressions', 'all-in-one-seo-pack' ),
'value' => aioseo()->helpers->compactNumber( $statistics['data']['statistics']['impressions'] ),
];
}
} catch ( \Exception $e ) {
// Do nothing.
}
}
return $parsed;
}
/**
* Retrieves the thumbnail URL.
*
* @since 4.7.2
*
* @param int $postId The post ID.
* @return string The post featured image URL (thumbnail size).
*/
private function getThumbnailUrl( $postId ) {
$imageUrl = get_the_post_thumbnail_url( $postId );
return $imageUrl ?: $this->featuredImagePlaceholder;
}
} Summary.php 0000666 00000022740 15114441267 0006730 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\EmailReports\Summary;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Summary class.
*
* @since 4.7.2
*/
class Summary {
/**
* The action hook to execute when the event is run.
*
* @since 4.7.2
*
* @var string
*/
public $actionHook = 'aioseo_report_summary';
/**
* Recipient for the email. Multiple recipients can be separated by a comma.
*
* @since 4.7.2
*
* @var string
*/
private $recipient;
/**
* Email chosen frequency. Can be either 'weekly' or 'monthly'.
*
* @since 4.7.2
*
* @var string
*/
private $frequency;
/**
* Class constructor.
*
* @since 4.7.2
*/
public function __construct() {
// No need to run any of this during a WP AJAX request.
if ( wp_doing_ajax() ) {
return;
}
// No need to keep trying scheduling unless on admin.
add_action( 'admin_init', [ $this, 'maybeSchedule' ], 20 );
add_action( $this->actionHook, [ $this, 'cronTrigger' ] );
}
/**
* The summary cron callback.
* Hooked into `{@see self::$actionHook}` action hook.
*
* @since 4.7.2
*
* @param string $frequency The frequency of the email.
* @return void
*/
public function cronTrigger( $frequency ) {
// Keep going only if the feature is enabled.
if (
! aioseo()->options->advanced->emailSummary->enable ||
! apply_filters( 'aioseo_report_summary_enable', true, $frequency )
) {
return;
}
// Get all recipients for the given frequency.
$recipients = wp_list_filter( aioseo()->options->advanced->emailSummary->recipients, [ 'frequency' => $frequency ] );
if ( ! $recipients ) {
return;
}
try {
// Get only the email addresses.
$recipients = array_column( $recipients, 'email' );
$this->run( [
'recipient' => implode( ',', $recipients ),
'frequency' => $frequency,
] );
} catch ( \Exception $e ) {
// Do nothing.
}
}
/**
* Trigger the sending of the summary.
*
* @since 4.7.2
*
* @param array $data All the initial data needed for the summary to be sent.
* @throws \Exception If the email could not be sent.
* @return void
*/
public function run( $data ) {
try {
$this->recipient = $data['recipient'] ?? '';
$this->frequency = $data['frequency'] ?? '';
aioseo()->emailReports->mail->send( $this->getRecipient(), $this->getSubject(), $this->getContentHtml(), $this->getHeaders() );
} catch ( \Exception $e ) {
throw new \Exception( esc_html( $e->getMessage() ), esc_html( $e->getCode() ) );
}
}
/**
* Maybe (re)schedule the summary.
*
* @since 4.7.2
*
* @return void
*/
public function maybeSchedule() {
$allowedFrequencies = $this->getAllowedFrequencies();
// Add at least 6 hours after the day starts.
$addToStart = HOUR_IN_SECONDS * 6;
// Add the timezone offset.
$addToStart -= aioseo()->helpers->getTimeZoneOffset();
// Add a random time offset to avoid all emails being sent at the same time. 1440 * 3 = 3 days range.
$addToStart += aioseo()->helpers->generateRandomTimeOffset( aioseo()->helpers->getSiteDomain( true ), 1440 * 3 ) * MINUTE_IN_SECONDS;
foreach ( $allowedFrequencies as $frequency => $data ) {
aioseo()->actionScheduler->scheduleRecurrent( $this->actionHook, $data['start'] + $addToStart, $data['interval'], compact( 'frequency' ) );
}
}
/**
* Get one or more valid recipients.
*
* @since 4.7.2
*
* @throws \Exception If no valid recipient was set for the email.
* @return string The valid recipients.
*/
private function getRecipient() {
$recipients = array_map( 'trim', explode( ',', $this->recipient ) );
$recipients = array_filter( $recipients, 'is_email' );
if ( empty( $recipients ) ) {
throw new \Exception( 'No valid recipient was set for the email.' ); // Not shown to the user.
}
return implode( ',', $recipients );
}
/**
* Get email subject.
*
* @since 4.7.2
*
* @return string The email subject.
*/
private function getSubject() {
// Translators: 1 - Date range.
$out = esc_html__( 'Your SEO Performance Report for %1$s', 'all-in-one-seo-pack' );
$dateRange = $this->getDateRange();
$suffix = date_i18n( 'F', $dateRange['endDateRaw'] );
if ( 'weekly' === $this->frequency ) {
$suffix = $dateRange['range'];
}
return sprintf( $out, $suffix );
}
/**
* Get content html.
*
* @since 4.7.2
*
* @return string The email content.
*/
private function getContentHtml() { // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$dateRange = $this->getDateRange();
$content = new Content( $dateRange );
$upsell = [
'search-statistics' => []
];
$preHeader = sprintf(
// Translators: 1 - The plugin short name ("AIOSEO").
esc_html__( 'Dive into your top-performing pages with %1$s and uncover growth opportunities.', 'all-in-one-seo-pack' ),
AIOSEO_PLUGIN_SHORT_NAME
);
$iconCalendar = 'weekly' === $this->frequency
? 'icon-calendar-weekly'
: 'icon-calendar-monthly';
$heading = 'weekly' === $this->frequency
? esc_html__( 'Your Weekly SEO Email Summary', 'all-in-one-seo-pack' )
: esc_html__( 'Your Monthly SEO Email Summary', 'all-in-one-seo-pack' );
$subheading = 'weekly' === $this->frequency
? esc_html__( 'Let\'s take a look at your SEO updates and content progress this week.', 'all-in-one-seo-pack' )
: esc_html__( 'Let\'s take a look at your SEO updates and content progress this month.', 'all-in-one-seo-pack' );
$statisticsReport = [
'posts' => [],
'keywords' => [],
'milestones' => [],
'cta' => [
'text' => esc_html__( 'See All SEO Statistics', 'all-in-one-seo-pack' ),
'url' => $content->searchStatisticsUrl
],
];
if ( ! $content->allowSearchStatistics() ) {
$upsell['search-statistics'] = [
'cta' => [
'text' => esc_html__( 'Unlock Search Statistics', 'all-in-one-seo-pack' ),
'url' => $content->searchStatisticsUrl,
],
];
}
if ( ! $upsell['search-statistics'] ) {
$subheading = 'weekly' === $this->frequency
? esc_html__( 'Let\'s take a look at how your site has performed in search results this week.', 'all-in-one-seo-pack' )
: esc_html__( 'Let\'s take a look at how your site has performed in search results this month.', 'all-in-one-seo-pack' );
$statisticsReport['posts'] = $content->getPostsStatistics();
$statisticsReport['keywords'] = $content->getKeywords();
$statisticsReport['milestones'] = $content->getMilestones();
}
$mktUrl = trailingslashit( AIOSEO_MARKETING_URL );
$medium = 'email-report-summary';
$posts = $content->getAioPosts();
$resources = [
'posts' => array_map( function ( $item ) use ( $medium, $content ) {
return array_merge( $item, [
'url' => aioseo()->helpers->utmUrl( $item['url'], $medium ),
'image' => [
'url' => ! empty( $item['image']['sizes']['medium']['source_url'] )
? $item['image']['sizes']['medium']['source_url']
: $content->featuredImagePlaceholder
]
] );
}, $content->getResources() ),
'cta' => [
'text' => esc_html__( 'See All Resources', 'all-in-one-seo-pack' ),
'url' => aioseo()->helpers->utmUrl( 'https://aioseo.com/blog/', $medium ),
],
];
$links = [
'disable' => admin_url( 'admin.php?page=aioseo-settings&aioseo-scroll=aioseo-email-summary-row&aioseo-highlight=aioseo-email-summary-row&aioseo-tab=advanced' ),
'update' => admin_url( 'update-core.php' ),
'marketing-site' => aioseo()->helpers->utmUrl( $mktUrl, $medium ),
'facebook' => aioseo()->helpers->utmUrl( $mktUrl . 'plugin/facebook', $medium ),
'linkedin' => aioseo()->helpers->utmUrl( $mktUrl . 'plugin/linkedin', $medium ),
'youtube' => aioseo()->helpers->utmUrl( $mktUrl . 'plugin/youtube', $medium ),
'twitter' => aioseo()->helpers->utmUrl( $mktUrl . 'plugin/twitter', $medium ),
];
ob_start();
require AIOSEO_DIR . '/app/Common/Views/report/summary.php';
return ob_get_clean();
}
/**
* Get email headers.
*
* @since 4.7.2
*
* @return array The email headers.
*/
private function getHeaders() {
return [ 'Content-Type: text/html; charset=UTF-8' ];
}
/**
* Get all allowed frequencies.
*
* @since 4.7.2
*
* @return array The email allowed frequencies.
*/
private function getAllowedFrequencies() {
$time = time();
$secondsTillNow = $time - strtotime( 'today' );
return [
'weekly' => [
'interval' => WEEK_IN_SECONDS,
'start' => strtotime( 'next Monday' ) - $time
],
'monthly' => [
'interval' => MONTH_IN_SECONDS,
'start' => ( strtotime( 'first day of next month' ) + ( DAY_IN_SECONDS * 2 ) - $secondsTillNow ) - $time
]
];
}
/**
* Retrieves the date range data based on the frequency.
*
* @since 4.7.3
*
* @return array The date range data.
*/
private function getDateRange() {
$dateFormat = get_option( 'date_format' );
// If frequency is 'monthly'.
$endDateRaw = strtotime( 'last day of last month' );
$startDateRaw = strtotime( 'first day of last month' );
// If frequency is 'weekly'.
if ( 'weekly' === $this->frequency ) {
$endDateRaw = strtotime( 'last Saturday' );
$startDateRaw = strtotime( 'last Sunday', $endDateRaw );
}
$endDate = date_i18n( $dateFormat, $endDateRaw );
$startDate = date_i18n( $dateFormat, $startDateRaw );
return [
'endDate' => $endDate,
'endDateRaw' => $endDateRaw,
'startDate' => $startDate,
'startDateRaw' => $startDateRaw,
'range' => "$startDate - $endDate",
];
}
}