| Current Path : /home/x/b/o/xbodynamge/namtation/wp-content/ |
| Current File : /home/x/b/o/xbodynamge/namtation/wp-content/Standalone.tar |
Standalone.php 0000666 00000005446 15114751622 0007366 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Pro\Standalone as ProStandalone;
/**
* Registers the standalone components.
*
* @since 4.2.0
*/
class Standalone {
/**
* HeadlineAnalyzer class instance.
*
* @since 4.2.7
*
* @var HeadlineAnalyzer
*/
public $headlineAnalyzer = null;
/**
* FlyoutMenu class instance.
*
* @since 4.2.7
*
* @var FlyoutMenu
*/
public $flyoutMenu = null;
/**
* SeoPreview class instance.
*
* @since 4.2.8
*
* @var SeoPreview
*/
public $seoPreview = null;
/**
* SetupWizard class instance.
*
* @since 4.2.7
*
* @var SetupWizard
*/
public $setupWizard = null;
/**
* PrimaryTerm class instance.
*
* @since 4.3.6
*
* @var PrimaryTerm
*/
public $primaryTerm = null;
/**
* UserProfileTab class instance.
*
* @since 4.5.4
*
* @var UserProfileTab
*/
public $userProfileTab = null;
/**
* BuddyPress class instance.
*
* @since 4.7.6
*
* @var BuddyPress\BuddyPress
*/
public $buddyPress = null;
/**
* BbPress class instance.
*
* @since 4.8.1
*
* @var BbPress\BbPress
*/
public $bbPress = null;
/**
* List of page builder integration class instances.
*
* @since 4.2.7
*
* @var array[Object]
*/
public $pageBuilderIntegrations = [];
/**
* List of block class instances.
*
* @since 4.2.7
*
* @var array[Object]
*/
public $standaloneBlocks = [];
/**
* Class constructor.
*
* @since 4.2.0
*/
public function __construct() {
$this->headlineAnalyzer = new HeadlineAnalyzer();
$this->flyoutMenu = new FlyoutMenu();
$this->seoPreview = new SeoPreview();
$this->setupWizard = new SetupWizard();
$this->primaryTerm = aioseo()->pro ? new ProStandalone\PrimaryTerm() : new PrimaryTerm();
$this->userProfileTab = new UserProfileTab();
$this->buddyPress = aioseo()->pro ? new ProStandalone\BuddyPress\BuddyPress() : new BuddyPress\BuddyPress();
$this->bbPress = aioseo()->pro ? new ProStandalone\BbPress\BbPress() : new BbPress\BbPress();
aioseo()->pro ? new ProStandalone\DetailsColumn() : new DetailsColumn();
new AdminBarNoindexWarning();
new LimitModifiedDate();
new Notifications();
new PublishPanel();
new WpCode();
$this->pageBuilderIntegrations = [
'elementor' => new PageBuilders\Elementor(),
'divi' => new PageBuilders\Divi(),
'seedprod' => new PageBuilders\SeedProd(),
'wpbakery' => new PageBuilders\WPBakery(),
'avada' => new PageBuilders\Avada(),
'siteorigin' => new PageBuilders\SiteOrigin(),
'thrive' => new PageBuilders\ThriveArchitect()
];
$this->standaloneBlocks = [
'tocBlock' => new Blocks\TableOfContents(),
'faqBlock' => new Blocks\FaqPage()
];
}
} HeadlineAnalyzer.php 0000666 00000040326 15114751622 0010511 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles the headline analysis.
*
* @since 4.1.2
*/
class HeadlineAnalyzer {
/**
* Class constructor.
*
* @since 4.1.2
*/
public function __construct() {
if ( ! is_admin() || wp_doing_cron() ) {
return;
}
add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue' ] );
if ( ! aioseo()->options->advanced->headlineAnalyzer ) {
return;
}
add_filter( 'monsterinsights_headline_analyzer_enabled', '__return_false' );
add_filter( 'exactmetrics_headline_analyzer_enabled', '__return_false' );
}
/**
* Enqueues the headline analyzer.
*
* @since 4.1.2
*
* @return void
*/
public function enqueue() {
if (
! aioseo()->helpers->isScreenBase( 'post' ) ||
! aioseo()->access->hasCapability( 'aioseo_page_analysis' )
) {
return;
}
if ( ! aioseo()->options->advanced->headlineAnalyzer ) {
return;
}
$path = '/vendor/jwhennessey/phpinsight/autoload.php';
if ( ! aioseo()->core->fs->exists( AIOSEO_DIR . $path ) ) {
return;
}
require AIOSEO_DIR . $path;
aioseo()->core->assets->load( 'src/vue/standalone/headline-analyzer/main.js' );
}
/**
* Returns the result of the analsyis.
*
* @since 4.1.2
*
* @param string $title The title.
* @return array The result.
*/
public function getResult( $title ) {
$result = $this->getHeadlineScore( html_entity_decode( $title ) );
return [
'result' => $result,
'analysed' => ! $result->err,
'sentence' => ucwords( wp_unslash( sanitize_text_field( $title ) ) ),
'score' => ! empty( $result->score ) ? $result->score : 0
];
}
/**
* Returns the score.
*
* @since 4.1.2
*
* @param string $title The title.
* @return \stdClass The result.
*/
public function getHeadlineScore( $title ) {
$result = new \stdClass();
$result->originalExplodedHeadline = explode( ' ', wp_unslash( $title ) );
// Strip useless characters and whitespace.
$title = preg_replace( '/[^A-Za-z0-9 ]/', '', (string) $title );
$title = preg_replace( '!\s+!', ' ', (string) $title );
$title = strtolower( $title );
$result->input = $title;
// If the headline is invalid, return an error.
if ( ! $title || ' ' === $title || trim( $title ) === '' ) {
$result->err = true;
$result->msg = 'The headline is invalid.';
return $result;
}
$totalScore = 0;
$explodedHeadline = explode( ' ', $title );
$result->explodedHeadline = $explodedHeadline;
$result->err = false;
// The optimal length is 55 characters.
$result->length = strlen( str_replace( ' ', '', $title ) );
$totalScore = $totalScore + 3;
//phpcs:disable Squiz.ControlStructures.ControlSignature
if ( $result->length <= 19 ) { $totalScore += 5; }
elseif ( $result->length >= 20 && $result->length <= 34 ) { $totalScore += 8; }
elseif ( $result->length >= 35 && $result->length <= 66 ) { $totalScore += 11; }
elseif ( $result->length >= 67 && $result->length <= 79 ) { $totalScore += 8; }
elseif ( $result->length >= 80 ) { $totalScore += 5; }
// The average headline is 6-7 words long.
$result->wordCount = count( $explodedHeadline );
$totalScore = $totalScore + 3;
if ( 0 === $result->wordCount ) { $totalScore = 0; }
elseif ( $result->wordCount >= 2 && $result->wordCount <= 4 ) { $totalScore += 5; }
elseif ( $result->wordCount >= 5 && $result->wordCount <= 9 ) { $totalScore += 11; }
elseif ( $result->wordCount >= 10 && $result->wordCount <= 11 ) { $totalScore += 8; }
elseif ( $result->wordCount >= 12 ) { $totalScore += 5; }
// Check for power words, emotional words, etc.
$result->powerWords = $this->matchWords( $result->input, $result->explodedHeadline, $this->powerWords() );
$result->powerWordsPercentage = count( $result->powerWords ) / $result->wordCount;
$result->emotionWords = $this->matchWords( $result->input, $result->explodedHeadline, $this->emotionPowerWords() );
$result->emotionalWordsPercentage = count( $result->emotionWords ) / $result->wordCount;
$result->commonWords = $this->matchWords( $result->input, $result->explodedHeadline, $this->commonWords() );
$result->commonWordsPercentage = count( $result->commonWords ) / $result->wordCount;
$result->uncommonWords = $this->matchWords( $result->input, $result->explodedHeadline, $this->uncommonWords() );
$result->uncommonWordsPercentage = count( $result->uncommonWords ) / $result->wordCount;
$result->detectedWordTypes = [];
if ( $result->emotionalWordsPercentage < 0.1 ) {
$result->detectedWordTypes[] = 'emotion';
} else {
$totalScore = $totalScore + 15;
}
if ( $result->commonWordsPercentage < 0.2 ) {
$result->detectedWordTypes[] = 'common';
} else {
$totalScore = $totalScore + 11;
}
if ( $result->uncommonWordsPercentage < 0.1 ) {
$result->detectedWordTypes[] = 'uncommon';
} else {
$totalScore = $totalScore + 15;
}
if ( count( $result->powerWords ) < 1 ) {
$result->detectedWordTypes[] = 'power';
} else {
$totalScore = $totalScore + 19;
}
if (
$result->emotionalWordsPercentage >= 0.1 &&
$result->commonWordsPercentage >= 0.2 &&
$result->uncommonWordsPercentage >= 0.1 &&
count( $result->powerWords ) >= 1
) {
$totalScore = $totalScore + 3;
}
$sentiment = new \PHPInsight\Sentiment();
$sentimentClass = $sentiment->categorise( $title );
$result->sentiment = $sentimentClass;
$totalScore = $totalScore + ( 'pos' === $result->sentiment ? 10 : ( 'neg' === $result->sentiment ? 10 : 7 ) );
$headlineTypes = [];
if ( strpos( $title, 'how to' ) !== false || strpos( $title, 'howto' ) !== false ) {
$headlineTypes[] = __( 'How-To', 'all-in-one-seo-pack' );
$totalScore = $totalScore + 7;
}
$listWords = array_intersect( $explodedHeadline, $this->numericalIndicators() );
if ( preg_match( '~[0-9]+~', (string) $title ) || ! empty( $listWords ) ) {
$headlineTypes[] = __( 'List', 'all-in-one-seo-pack' );
$totalScore = $totalScore + 7;
}
if ( in_array( $explodedHeadline[0], $this->primaryQuestionIndicators(), true ) ) {
if ( in_array( $explodedHeadline[1], $this->secondaryQuestionIndicators(), true ) ) {
$headlineTypes[] = __( 'Question', 'all-in-one-seo-pack' );
$totalScore = $totalScore + 7;
}
}
if ( empty( $headlineTypes ) ) {
$headlineTypes[] = __( 'General', 'all-in-one-seo-pack' );
$totalScore = $totalScore + 5;
}
$result->headlineTypes = $headlineTypes;
$result->score = $totalScore >= 93 ? 93 : $totalScore;
return $result;
}
/**
* Tries to find matches for power words, emotional words, etc. in the headline.
*
* @since 4.1.2
*
* @param string $headline The headline.
* @param array $explodedHeadline The exploded headline.
* @param array $words The words to match.
* @return array The matches that were found.
*/
public function matchWords( $headline, $explodedHeadline, $words ) {
$foundMatches = [];
foreach ( $words as $word ) {
$strippedWord = preg_replace( '/[^A-Za-z0-9 ]/', '', (string) $word );
// Check if word is a phrase.
if ( strpos( $word, ' ' ) !== false ) {
if ( strpos( $headline, $strippedWord ) !== false ) {
$foundMatches[] = $word;
}
continue;
}
// Check if it is a single word.
if ( in_array( $strippedWord, $explodedHeadline, true ) ) {
$foundMatches[] = $word;
}
}
return $foundMatches;
}
/**
* Returns a list of numerical indicators.
*
* @since 4.1.2
*
* @return array The list of numerical indicators.
*/
private function numericalIndicators() {
return [
'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'eleven', 'twelve', 'thirt', 'fift', 'hundred', 'thousand' // phpcs:ignore Generic.Files.LineLength.MaxExceeded, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine
];
}
/**
* Returns a list of primary question indicators.
*
* @since 4.1.2
*
* @return array The list of primary question indicators.
*/
private function primaryQuestionIndicators() {
return [
'where', 'when', 'how', 'what', 'have', 'has', 'does', 'do', 'can', 'are', 'will' // phpcs:ignore Generic.Files.LineLength.MaxExceeded, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine
];
}
/**
* Returns a list of secondary question indicators.
*
* @since 4.1.2
*
* @return array The list of secondary question indicators.
*/
private function secondaryQuestionIndicators() {
return [
'you', 'they', 'he', 'she', 'your', 'it', 'they', 'my', 'have', 'has', 'does', 'do', 'can', 'are', 'will' // phpcs:ignore Generic.Files.LineLength.MaxExceeded, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine
];
}
/**
* Returns a list of power words.
*
* @since 4.1.2
*
* @return array The list of power words.
*/
private function powerWords() {
return [
'great', 'free', 'focus', 'remarkable', 'confidential', 'sale', 'wanted', 'obsession', 'sizable', 'new', 'absolutely lowest', 'surging', 'wonderful', 'professional', 'interesting', 'revisited', 'delivered', 'guaranteed', 'challenge', 'unique', 'secrets', 'special', 'lifetime', 'bargain', 'scarce', 'tested', 'highest', 'hurry', 'alert famous', 'improved', 'expert', 'daring', 'strong', 'immediately', 'advice', 'pioneering', 'unusual', 'limited', 'the truth about', 'destiny', 'outstanding', 'simplistic', 'compare', 'unsurpassed', 'energy', 'powerful', 'colorful', 'genuine', 'instructive', 'big', 'affordable', 'informative', 'liberal', 'popular', 'ultimate', 'mainstream', 'rare', 'exclusive', 'willpower', 'complete', 'edge', 'valuable', 'attractive', 'last chance', 'superior', 'how to', 'easily', 'exploit', 'unparalleled', 'endorsed', 'approved', 'quality', 'fascinating', 'unlimited', 'competitive', 'gigantic', 'compromise', 'discount', 'full', 'love', 'odd', 'fundamentals', 'mammoth', 'lavishly', 'bottom line', 'under priced', 'innovative', 'reliable', 'zinger', 'suddenly', 'it\'s here', 'terrific', 'simplified', 'perspective', 'just arrived', 'breakthrough', 'tremendous', 'launching', 'sure fire', 'emerging', 'helpful', 'skill', 'soar', 'profitable', 'special offer', 'reduced', 'beautiful', 'sampler', 'technology', 'better', 'crammed', 'noted', 'selected', 'shrewd', 'growth', 'luxury', 'sturdy', 'enormous', 'promising', 'unconditional', 'wealth', 'spotlight', 'astonishing', 'timely', 'successful', 'useful', 'imagination', 'bonanza', 'opportunities', 'survival', 'greatest', 'security', 'last minute', 'largest', 'high tech', 'refundable', 'monumental', 'colossal', 'latest', 'quickly', 'startling', 'now', 'important', 'revolutionary', 'quick', 'unlock', 'urgent', 'miracle', 'easy', 'fortune', 'amazing', 'magic', 'direct', 'authentic', 'exciting', 'proven', 'simple', 'announcing', 'portfolio', 'reward', 'strange', 'huge gift', 'revealing', 'weird', 'value', 'introducing', 'sensational', 'surprise', 'insider', 'practical', 'excellent', 'delighted', 'download' // phpcs:ignore Generic.Files.LineLength.MaxExceeded, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine
];
}
/**
* Returns a list of common words.
*
* @since 4.1.2
*
* @return array The list of common words.
*/
private function commonWords() {
return [
'a', 'for', 'about', 'from', 'after', 'get', 'all', 'has', 'an', 'have', 'and', 'he', 'are', 'her', 'as', 'his', 'at', 'how', 'be', 'I', 'but', 'if', 'by', 'in', 'can', 'is', 'did', 'it', 'do', 'just', 'ever', 'like', 'll', 'these', 'me', 'they', 'most', 'things', 'my', 'this', 'no', 'to', 'not', 'up', 'of', 'was', 'on', 'what', 're', 'when', 'she', 'who', 'sould', 'why', 'so', 'will', 'that', 'with', 'the', 'you', 'their', 'your', 'there' // phpcs:ignore Generic.Files.LineLength.MaxExceeded, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine
];
}
/**
* Returns a list of uncommon words.
*
* @since 4.1.2
*
* @return array The list of uncommon words.
*/
private function uncommonWords() {
return [
'actually', 'happened', 'need', 'thing', 'awesome', 'heart', 'never', 'think', 'baby', 'here', 'new', 'time', 'beautiful', 'its', 'now', 'valentines', 'being', 'know', 'old', 'video', 'best', 'life', 'one', 'want', 'better', 'little', 'out', 'watch', 'boy', 'look', 'people', 'way', 'dog', 'love', 'photos', 'ways', 'down', 'made', 'really', 'world', 'facebook', 'make', 'reasons', 'year', 'first', 'makes', 'right', 'years', 'found', 'man', 'see', 'you’ll', 'girl', 'media', 'seen', 'good', 'mind', 'social', 'guy', 'more', 'something' // phpcs:ignore Generic.Files.LineLength.MaxExceeded, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine
];
}
/**
* Returns a list of emotional power words.
*
* @since 4.1.2
*
* @return array The list of emotional power words.
*/
private function emotionPowerWords() {
return [
'destroy', 'extra', 'in a', 'devastating', 'eye-opening', 'gift', 'in the world', 'devoted', 'fail', 'in the', 'faith', 'grateful', 'inexpensive', 'dirty', 'famous', 'disastrous', 'fantastic', 'greed', 'grit', 'insanely', 'disgusting', 'fearless', 'disinformation', 'feast', 'insidious', 'dollar', 'feeble', 'gullible', 'double', 'fire', 'hack', 'fleece', 'had enough', 'invasion', 'drowning', 'floundering', 'happy', 'ironclad', 'dumb', 'flush', 'hate', 'irresistibly', 'hazardous', 'is the', 'fool', 'is what happens when', 'fooled', 'helpless', 'it looks like a', 'embarrass', 'for the first time', 'help are the', 'jackpot', 'forbidden', 'hidden', 'jail', 'empower', 'force-fed', 'high', 'jaw-dropping', 'forgotten', 'jeopardy', 'energize', 'hoax', 'jubilant', 'foul', 'hope', 'killer', 'frantic', 'horrific', 'know it all', 'epic', 'how to make', 'evil', 'freebie', 'frenzy', 'hurricane', 'excited', 'fresh on the mind', 'frightening', 'hypnotic', 'lawsuit', 'frugal', 'illegal', 'fulfill', 'lick', 'explode', 'lies', 'exposed', 'gambling', 'like a normal', 'nightmare', 'results', 'line', 'no good', 'pound', 'loathsome', 'no questions asked', 'revenge', 'lonely', 'looks like a', 'obnoxious', 'preposterous', 'revolting', 'looming', 'priced', 'lost', 'prison', 'lowest', 'of the', 'privacy', 'rich', 'lunatic', 'off-limits', 'private', 'risky', 'lurking', 'offer', 'prize', 'ruthless', 'lust', 'official', 'luxurious', 'on the', 'profit', 'scary', 'lying', 'outlawed', 'protected', 'scream', 'searing', 'overcome', 'provocative', 'make you', 'painful', 'pummel', 'secure', 'pale', 'punish', 'marked down', 'panic', 'quadruple', 'seductively', 'massive', 'pay zero', 'seize', 'meltdown', 'payback', 'might look like a', 'peril', 'mind-blowing', 'shameless', 'minute', 'rave', 'shatter', 'piranha', 'reckoning', 'shellacking', 'mired', 'pitfall', 'reclaim', 'mistakes', 'plague', 'sick and tired', 'money', 'played', 'refugee', 'silly', 'money-grubbing', 'pluck', 'refund', 'moneyback', 'plummet', 'plunge', 'murder', 'pointless', 'sinful', 'myths', 'poor', 'remarkably', 'six-figure', 'never again', 'research', 'surrender', 'to the', 'varify', 'skyrocket', 'toxic', 'vibrant', 'slaughter', 'swindle', 'trap', 'victim', 'sleazy', 'taboo', 'treasure', 'victory', 'smash', 'tailspin', 'vindication', 'smug', 'tank', 'triple', 'viral', 'smuggled', 'tantalizing', 'triumph', 'volatile', 'sniveling', 'targeted', 'truth', 'vulnerable', 'snob', 'tawdry', 'try before you buy', 'tech', 'turn the tables', 'wanton', 'soaring', 'warning', 'teetering', 'unauthorized', 'spectacular', 'temporary fix', 'unbelievably', 'spine', 'tempting', 'uncommonly', 'what happened', 'spirit', 'what happens when', 'terror', 'under', 'what happens', 'staggering', 'underhanded', 'what this', 'that will make you', 'undo","when you see', 'that will make', 'unexpected', 'when you', 'strangle', 'that will', 'whip', 'the best', 'whopping', 'stuck up', 'the ranking of', 'wicked', 'stunning', 'the most', 'will make you', 'stupid', 'the reason why is', 'unscrupulous', 'thing ive ever seen', 'withheld', 'this is the', 'this is what happens', 'unusually', 'wondrous', 'this is what', 'uplifting', 'worry', 'sure', 'this is', 'wounded', 'surge', 'thrilled', 'you need to know', 'thrilling', 'valor', 'you need to', 'you see what', 'surprising', 'tired', 'you see', 'surprisingly', 'to be', 'vaporize' // phpcs:ignore Generic.Files.LineLength.MaxExceeded, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine
];
}
} Notifications.php 0000666 00000001357 15114751622 0010104 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* Handles the notifications standalone.
*
* @since 4.2.0
*/
class Notifications {
/**
* Class constructor.
*
* @since 4.2.0
*/
public function __construct() {
if ( ! is_admin() ) {
return;
}
add_action( 'admin_enqueue_scripts', [ $this, 'enqueueScript' ] );
}
/**
* Enqueues the script.
*
* @since 4.2.0
*
* @return void
*/
public function enqueueScript() {
aioseo()->core->assets->load( 'src/vue/standalone/notifications/main.js', [], [
'newNotifications' => count( Models\Notification::getNewNotifications() )
], 'aioseoNotifications' );
}
} PrimaryTerm.php 0000666 00000002402 15114751622 0007536 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles the Primary Term feature.
*
* @since 4.3.6
*/
class PrimaryTerm {
/**
* Class constructor.
*
* @since 4.3.6
*/
public function __construct() {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
if ( wp_doing_ajax() || wp_doing_cron() || ! is_admin() ) {
return;
}
add_action( 'admin_enqueue_scripts', [ $this, 'enqueueAssets' ] );
}
/**
* Enqueues the JS/CSS for the on page/posts settings.
*
* @since 4.3.6
*
* @return void
*/
public function enqueueAssets() {
if ( ! aioseo()->helpers->isScreenBase( 'post' ) ) {
return;
}
aioseo()->core->assets->load( 'src/vue/standalone/primary-term/main.js', [], aioseo()->helpers->getVueData( 'post' ) );
}
/**
* Returns the primary term for the given taxonomy name.
*
* @since 4.3.6
*
* @param int $postId The post ID.
* @param string $taxonomyName The taxonomy name.
* @return \WP_Term|false The term or false.
*/
public function getPrimaryTerm( $postId, $taxonomyName ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
return false;
}
} AdminBarNoindexWarning.php 0000666 00000003166 15114751622 0011623 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* Handles the admin bar noindex warning.
*
* @since 4.6.7
*/
class AdminBarNoindexWarning {
/**
* Class constructor.
*
* @since 4.6.7
*/
public function __construct() {
add_action( 'init', [ $this, 'init' ] );
}
/**
* Initializes the standalone.
*
* @since 4.6.7
*
* @return void
*/
public function init() {
if ( wp_doing_ajax() || wp_doing_cron() ) {
return;
}
$isSitePublic = get_option( 'blog_public' );
if ( $isSitePublic ) {
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
add_action( 'admin_enqueue_scripts', [ $this, 'enqueueScript' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueueScript' ] );
add_action( 'admin_bar_menu', [ $this, 'addAdminBarElement' ], 99999 );
}
/**
* Enqueues the script.
*
* @since 4.6.7
*
* @return void
*/
public function enqueueScript() {
aioseo()->core->assets->load( 'src/vue/standalone/admin-bar-noindex-warning/main.js', [], [
'optionsReadingUrl' => admin_url( 'options-reading.php' ),
], 'aioseoAdminBarNoindexWarning' );
}
/**
* Adds the admin bar element.
*
* @since 4.6.7
*
* @param \WP_Admin_Bar $wpAdminBar The admin bar object.
* @return void
*/
public function addAdminBarElement( $wpAdminBar ) {
$wpAdminBar->add_node(
[
'id' => 'aioseo-admin-bar-noindex-warning',
'title' => __( 'Search Engines Blocked!', 'all-in-one-seo-pack' ),
'href' => admin_url( 'options-reading.php' )
]
);
}
} SeoPreview.php 0000666 00000021725 15114751622 0007364 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
use AIOSEO\Plugin\Common\Integrations\BuddyPress as BuddyPressIntegration;
/**
* Handles the SEO Preview feature on the front-end.
*
* @since 4.2.8
*/
class SeoPreview {
/**
* Whether this feature is allowed on the current page or not.
*
* @since 4.2.8
*
* @var bool
*/
private $enable = false;
/**
* The relative JS filename for this standalone.
*
* @since 4.3.1
*
* @var string
*/
private $mainAssetRelativeFilename = 'src/vue/standalone/seo-preview/main.js';
/**
* Class constructor.
*
* @since 4.2.8
*/
public function __construct() {
// Allow users to disable SEO Preview.
if ( apply_filters( 'aioseo_seo_preview_disable', false ) ) {
return;
}
// Hook into `wp` in order to have access to the WP queried object.
add_action( 'wp', [ $this, 'init' ], 20 );
}
/**
* Initialize the feature.
* Hooked into `wp` action hook.
*
* @since 4.2.8
*
* @return void
*/
public function init() {
if (
is_admin() ||
! aioseo()->helpers->isAdminBarEnabled() ||
// If we're seeing the Divi theme Visual Builder.
( function_exists( 'et_core_is_fb_enabled' ) && et_core_is_fb_enabled() ) ||
aioseo()->helpers->isAmpPage()
) {
return;
}
$allow = [
'archive',
'attachment',
'author',
'date',
'dynamic_home',
'page',
'search',
'single',
'taxonomy',
];
if ( ! in_array( aioseo()->helpers->getTemplateType(), $allow, true ) ) {
return;
}
$this->enable = true;
// Prevent Autoptimize from optimizing the translations for the SEO Preview. If we don't do this, Autoptimize can break the frontend for certain languages - #5235.
if ( is_user_logged_in() && 'en_US' !== get_user_locale() ) {
add_filter( 'autoptimize_filter_noptimize', '__return_true' );
}
// As WordPress uses priority 10 to print footer scripts we use 9 to make sure our script still gets output.
add_action( 'wp_print_footer_scripts', [ $this, 'enqueueScript' ], 9 );
}
/**
* Hooked into `wp_print_footer_scripts` action hook.
* Enqueue the standalone JS the latest possible and prevent 3rd-party performance plugins from merging it.
*
* @since 4.3.1
*
* @return void
*/
public function enqueueScript() {
aioseo()->core->assets->load( $this->mainAssetRelativeFilename, [], $this->getVueData(), 'aioseoSeoPreview' );
aioseo()->main->enqueueTranslations();
}
/**
* Returns the data for Vue.
*
* @since 4.2.8
*
* @return array The data.
*/
private function getVueData() {
$data = [
'editGoogleSnippetUrl' => '',
'editFacebookSnippetUrl' => '',
'editTwitterSnippetUrl' => '',
'editObjectBtnText' => '',
'editObjectUrl' => '',
'keyphrases' => '',
'page_analysis' => '',
'urls' => [
'home' => home_url(),
'domain' => aioseo()->helpers->getSiteDomain(),
'mainSiteUrl' => aioseo()->helpers->getSiteUrl(),
],
'mainAssetCssQueue' => aioseo()->core->assets->getJsAssetCssQueue( $this->mainAssetRelativeFilename ),
'data' => [
'isDev' => aioseo()->helpers->isDev(),
'siteName' => aioseo()->helpers->getWebsiteName(),
'usingPermalinks' => aioseo()->helpers->usingPermalinks()
]
];
if ( BuddyPressIntegration::isComponentPage() ) {
return array_merge( $data, aioseo()->standalone->buddyPress->getVueDataSeoPreview() );
}
$queriedObject = get_queried_object(); // Don't use the getTerm helper here.
$templateType = aioseo()->helpers->getTemplateType();
if (
'taxonomy' === $templateType ||
'single' === $templateType ||
'page' === $templateType ||
'attachment' === $templateType
) {
$labels = null;
if ( is_a( $queriedObject, 'WP_Term' ) ) {
$wpObject = $queriedObject;
$labels = get_taxonomy_labels( get_taxonomy( $queriedObject->taxonomy ) );
$data['editObjectUrl'] = get_edit_term_link( $queriedObject, $queriedObject->taxonomy );
} else {
$wpObject = aioseo()->helpers->getPost();
if ( is_a( $wpObject, 'WP_Post' ) ) {
$labels = get_post_type_labels( get_post_type_object( $wpObject->post_type ) );
$data['editObjectUrl'] = get_edit_post_link( $wpObject, 'url' );
if (
! aioseo()->helpers->isSpecialPage( $wpObject->ID ) &&
'attachment' !== $templateType
) {
$aioseoPost = Models\Post::getPost( $wpObject->ID );
$data['page_analysis'] = Models\Post::getPageAnalysisDefaults( $aioseoPost->page_analysis );
$data['keyphrases'] = Models\Post::getKeyphrasesDefaults( $aioseoPost->keyphrases );
}
}
}
// At this point if `$wpObject` is not an instance of WP_Term nor WP_Post, then we can't have the URLs.
if (
is_object( $wpObject ) &&
is_object( $labels )
) {
$data['editObjectBtnText'] = sprintf(
// Translators: 1 - A noun for something that's being edited ("Post", "Page", "Article", "Product", etc.).
esc_html__( 'Edit %1$s', 'all-in-one-seo-pack' ),
$labels->singular_name
);
$data['editGoogleSnippetUrl'] = $this->getEditSnippetUrl( $templateType, 'google', $wpObject );
$data['editFacebookSnippetUrl'] = $this->getEditSnippetUrl( $templateType, 'facebook', $wpObject );
$data['editTwitterSnippetUrl'] = $this->getEditSnippetUrl( $templateType, 'twitter', $wpObject );
}
}
if (
'archive' === $templateType ||
'author' === $templateType ||
'date' === $templateType ||
'search' === $templateType
) {
if ( is_a( $queriedObject, 'WP_User' ) ) {
$data['editObjectUrl'] = get_edit_user_link( $queriedObject->ID );
$data['editObjectBtnText'] = esc_html__( 'Edit User', 'all-in-one-seo-pack' );
}
$data['editGoogleSnippetUrl'] = $this->getEditSnippetUrl( $templateType, 'google' );
}
if ( 'dynamic_home' === $templateType ) {
$data['editGoogleSnippetUrl'] = $this->getEditSnippetUrl( $templateType, 'google' );
$data['editFacebookSnippetUrl'] = $this->getEditSnippetUrl( $templateType, 'facebook' );
$data['editTwitterSnippetUrl'] = $this->getEditSnippetUrl( $templateType, 'twitter' );
}
return $data;
}
/**
* Get the URL to the place where the snippet details can be edited.
*
* @since 4.2.8
*
* @param string $templateType The WP template type {@see WpContext::getTemplateType}.
* @param string $snippet 'google', 'facebook' or 'twitter'.
* @param \WP_Post|\WP_Term|null $object Post or term object.
* @return string The URL. Returns an empty string if nothing matches.
*/
private function getEditSnippetUrl( $templateType, $snippet, $object = null ) {
$url = '';
// Bail if `$snippet` doesn't fit requirements.
if ( ! in_array( $snippet, [ 'google', 'facebook', 'twitter' ], true ) ) {
return $url;
}
// If we're in a post/page/term (not an attachment) we'll have a URL directly to the meta box.
if ( in_array( $templateType, [ 'single', 'page', 'attachment', 'taxonomy' ], true ) ) {
$url = 'taxonomy' === $templateType
? get_edit_term_link( $object, $object->taxonomy ) . '#aioseo-term-settings-field'
: get_edit_post_link( $object, 'url' ) . '#aioseo-settings';
$queryArgs = [ 'aioseo-tab' => 'general' ];
if ( in_array( $snippet, [ 'facebook', 'twitter' ], true ) ) {
$queryArgs = [
'aioseo-tab' => 'social',
'social-tab' => $snippet
];
}
return add_query_arg( $queryArgs, $url );
}
// If we're in any sort of archive let's point to the global archive editing.
if ( in_array( $templateType, [ 'archive', 'author', 'date', 'search' ], true ) ) {
return admin_url( 'admin.php?page=aioseo-search-appearance' ) . '#/archives';
}
// If homepage is set to show the latest posts let's point to the global home page editing.
if ( 'dynamic_home' === $templateType ) {
// Default `$url` for 'google' snippet.
$url = add_query_arg(
[ 'aioseo-scroll' => 'home-page-settings' ],
admin_url( 'admin.php?page=aioseo-search-appearance' ) . '#/global-settings'
);
if ( in_array( $snippet, [ 'facebook', 'twitter' ], true ) ) {
$url = admin_url( 'admin.php?page=aioseo-social-networks' ) . '#/' . $snippet;
}
return $url;
}
return $url;
}
/**
* Returns the "SEO Preview" submenu item data ("node" as WP calls it).
*
* @since 4.2.8
*
* @return array The admin bar menu item data or an empty array if this feature is disabled.
*/
public function getAdminBarMenuItemNode() {
if ( ! $this->enable ) {
return [];
}
$title = esc_html__( 'SEO Preview', 'all-in-one-seo-pack' );
// @TODO Remove 'NEW' after a couple months.
$title .= '<span class="aioseo-menu-new-indicator">';
$title .= esc_html__( 'NEW', 'all-in-one-seo-pack' ) . '!';
$title .= '</span>';
return [
'id' => 'aioseo-seo-preview',
'parent' => 'aioseo-main',
'title' => $title,
'href' => '#',
];
}
} BuddyPress/Sitemap.php 0000666 00000015654 15114751622 0010766 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\BuddyPress;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Integrations\BuddyPress as BuddyPressIntegration;
/**
* BuddyPress Sitemap class.
*
* @since 4.7.6
*/
class Sitemap {
/**
* Returns the indexes for the sitemap root index.
*
* @since 4.7.6
*
* @return array The indexes.
*/
public function indexes() {
$indexes = [];
$includedPostTypes = array_flip( aioseo()->sitemap->helpers->includedPostTypes() );
$filterPostTypes = array_filter( [
BuddyPressIntegration::isComponentActive( 'activity' ) && isset( $includedPostTypes['bp-activity'] ) ? 'bp-activity' : '',
BuddyPressIntegration::isComponentActive( 'group' ) && isset( $includedPostTypes['bp-group'] ) ? 'bp-group' : '',
BuddyPressIntegration::isComponentActive( 'member' ) && isset( $includedPostTypes['bp-member'] ) ? 'bp-member' : '',
] );
foreach ( $filterPostTypes as $postType ) {
$indexes = array_merge( $indexes, $this->buildIndexesPostType( $postType ) );
}
return $indexes;
}
/**
* Builds BuddyPress related root indexes.
*
* @since 4.7.6
*
* @param string $postType The BuddyPress fake post type.
* @return array The BuddyPress related root indexes.
*/
private function buildIndexesPostType( $postType ) {
switch ( $postType ) {
case 'bp-activity':
return $this->buildIndexesActivity();
case 'bp-group':
return $this->buildIndexesGroup();
case 'bp-member':
return $this->buildIndexesMember();
default:
return [];
}
}
/**
* Builds activity root indexes.
*
* @since 4.7.6
*
* @return array The activity root indexes.
*/
private function buildIndexesActivity() {
$activityTable = aioseo()->core->db->prefix . 'bp_activity';
$linksPerIndex = aioseo()->sitemap->linksPerIndex;
$items = aioseo()->core->db->execute(
aioseo()->core->db->db->prepare(
"SELECT id, date_recorded
FROM (
SELECT @row := @row + 1 AS rownum, id, date_recorded
FROM (
SELECT a.id, a.date_recorded FROM $activityTable as a
WHERE a.is_spam = 0
AND a.hide_sitewide = 0
AND a.type NOT IN ('activity_comment', 'last_activity')
ORDER BY a.date_recorded DESC
) AS x
CROSS JOIN (SELECT @row := 0) AS vars
ORDER BY date_recorded DESC
) AS y
WHERE rownum = 1 OR rownum % %d = 1;",
[
$linksPerIndex
]
),
true
)->result();
$totalItems = aioseo()->core->db->execute(
"SELECT COUNT(*) as count
FROM $activityTable as a
WHERE a.is_spam = 0
AND a.hide_sitewide = 0
AND a.type NOT IN ('activity_comment', 'last_activity')
",
true
)->result();
$indexes = [];
if ( $items ) {
$filename = aioseo()->sitemap->filename;
$count = count( $items );
for ( $i = 0; $i < $count; $i++ ) {
$indexNumber = 0 !== $i && 1 < $count ? $i + 1 : '';
$indexes[] = [
'loc' => aioseo()->helpers->localizedUrl( "/bp-activity-$filename$indexNumber.xml" ),
'lastmod' => aioseo()->helpers->dateTimeToIso8601( $items[ $i ]->date_recorded ),
'count' => $linksPerIndex
];
}
// We need to update the count of the last index since it won't necessarily be the same as the links per index.
$indexes[ count( $indexes ) - 1 ]['count'] = $totalItems[0]->count - ( $linksPerIndex * ( $count - 1 ) );
}
return $indexes;
}
/**
* Builds group root indexes.
*
* @since 4.7.6
*
* @return array The group root indexes.
*/
private function buildIndexesGroup() {
$groupsTable = aioseo()->core->db->prefix . 'bp_groups';
$groupsMetaTable = aioseo()->core->db->prefix . 'bp_groups_groupmeta';
$linksPerIndex = aioseo()->sitemap->linksPerIndex;
$items = aioseo()->core->db->execute(
aioseo()->core->db->db->prepare(
"SELECT id, date_modified
FROM (
SELECT @row := @row + 1 AS rownum, id, date_modified
FROM (
SELECT g.id, gm.group_id, MAX(gm.meta_value) as date_modified FROM $groupsTable as g
INNER JOIN $groupsMetaTable AS gm ON g.id = gm.group_id
WHERE g.status = 'public'
AND gm.meta_key = 'last_activity'
GROUP BY g.id
ORDER BY date_modified DESC
) AS x
CROSS JOIN (SELECT @row := 0) AS vars
ORDER BY date_modified DESC
) AS y
WHERE rownum = 1 OR rownum % %d = 1;",
[
$linksPerIndex
]
),
true
)->result();
$totalItems = aioseo()->core->db->execute(
"SELECT COUNT(*) as count
FROM $groupsTable as g
WHERE g.status = 'public'
",
true
)->result();
$indexes = [];
if ( $items ) {
$filename = aioseo()->sitemap->filename;
$count = count( $items );
for ( $i = 0; $i < $count; $i++ ) {
$indexNumber = 0 !== $i && 1 < $count ? $i + 1 : '';
$indexes[] = [
'loc' => aioseo()->helpers->localizedUrl( "/bp-group-$filename$indexNumber.xml" ),
'lastmod' => aioseo()->helpers->dateTimeToIso8601( $items[ $i ]->date_modified ),
'count' => $linksPerIndex
];
}
// We need to update the count of the last index since it won't necessarily be the same as the links per index.
$indexes[ count( $indexes ) - 1 ]['count'] = $totalItems[0]->count - ( $linksPerIndex * ( $count - 1 ) );
}
return $indexes;
}
/**
* Builds member root indexes.
*
* @since 4.7.6
*
* @return array The member root indexes.
*/
private function buildIndexesMember() {
$activityTable = aioseo()->core->db->prefix . 'bp_activity';
$linksPerIndex = aioseo()->sitemap->linksPerIndex;
$items = aioseo()->core->db->execute(
aioseo()->core->db->db->prepare(
"SELECT user_id, date_recorded
FROM (
SELECT @row := @row + 1 AS rownum, user_id, date_recorded
FROM (
SELECT a.user_id, a.date_recorded FROM $activityTable as a
WHERE a.component = 'members'
AND a.type = 'last_activity'
ORDER BY a.date_recorded DESC
) AS x
CROSS JOIN (SELECT @row := 0) AS vars
ORDER BY date_recorded DESC
) AS y
WHERE rownum = 1 OR rownum % %d = 1;",
[
$linksPerIndex
]
),
true
)->result();
$totalItems = aioseo()->core->db->execute(
"SELECT COUNT(*) as count
FROM $activityTable as a
WHERE a.component = 'members'
AND a.type = 'last_activity'
",
true
)->result();
$indexes = [];
if ( $items ) {
$filename = aioseo()->sitemap->filename;
$count = count( $items );
for ( $i = 0; $i < $count; $i++ ) {
$indexNumber = 0 !== $i && 1 < $count ? $i + 1 : '';
$indexes[] = [
'loc' => aioseo()->helpers->localizedUrl( "/bp-member-$filename$indexNumber.xml" ),
'lastmod' => aioseo()->helpers->dateTimeToIso8601( $items[ $i ]->date_recorded ),
'count' => $linksPerIndex
];
}
// We need to update the count of the last index since it won't necessarily be the same as the links per index.
$indexes[ count( $indexes ) - 1 ]['count'] = $totalItems[0]->count - ( $linksPerIndex * ( $count - 1 ) );
}
return $indexes;
}
} BuddyPress/Component.php 0000666 00000030273 15114751622 0011320 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\BuddyPress;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Integrations\BuddyPress as BuddyPressIntegration;
use AIOSEO\Plugin\Common\Schema\Graphs as CommonGraphs;
/**
* BuddyPress Component class.
*
* @since 4.7.6
*/
class Component {
/**
* The current component template type.
*
* @since 4.7.6
*
* @var string|null
*/
public $templateType = null;
/**
* The component ID.
*
* @since 4.7.6
*
* @var int
*/
public $id = 0;
/**
* The component author.
*
* @since 4.7.6
*
* @var \WP_User|false
*/
public $author = false;
/**
* The component date.
*
* @since 4.7.6
*
* @var int|false
*/
public $date = false;
/**
* The activity single page data.
*
* @since 4.7.6
*
* @var array
*/
public $activity = [];
/**
* The group single page data.
*
* @since 4.7.6
*
* @var array
*/
public $group = [];
/**
* The type of the group archive page.
*
* @since 4.7.6
*
* @var array
*/
public $groupType = [];
/**
* Class constructor.
*
* @since 4.7.6
*/
public function __construct() {
if ( is_admin() ) {
return;
}
$this->setTemplateType();
$this->setId();
$this->setAuthor();
$this->setDate();
$this->setActivity();
$this->setGroup();
$this->setGroupType();
}
/**
* Sets the template type.
*
* @since 4.7.6
*
* @return void
*/
private function setTemplateType() {
if ( BuddyPressIntegration::callFunc( 'bp_is_single_activity' ) ) {
$this->templateType = 'bp-activity_single';
} elseif ( BuddyPressIntegration::callFunc( 'bp_is_group' ) ) {
$this->templateType = 'bp-group_single';
} elseif (
BuddyPressIntegration::callFunc( 'bp_is_user' ) &&
false === BuddyPressIntegration::callFunc( 'bp_is_single_activity' )
) {
$this->templateType = 'bp-member_single';
} elseif ( BuddyPressIntegration::callFunc( 'bp_is_activity_directory' ) ) {
$this->templateType = 'bp-activity_archive';
} elseif ( BuddyPressIntegration::callFunc( 'bp_is_members_directory' ) ) {
$this->templateType = 'bp-member_archive';
} elseif ( BuddyPressIntegration::callFunc( 'bp_is_groups_directory' ) ) {
$this->templateType = 'bp-group_archive';
} elseif (
BuddyPressIntegration::callFunc( 'bp_is_current_action', 'feed' ) &&
BuddyPressIntegration::callFunc( 'bp_is_activity_component' )
) {
$this->templateType = 'bp-activity_feed';
}
}
/**
* Sets the component ID.
*
* @since 4.7.6
*
* @return void
*/
private function setId() {
switch ( $this->templateType ) {
case 'bp-activity_single':
$id = get_query_var( 'bp_member_action' );
break;
case 'bp-group_single':
$id = get_query_var( 'bp_group' );
break;
case 'bp-member_single':
$id = get_query_var( 'bp_member' );
break;
default:
$id = $this->id;
}
$this->id = $id;
}
/**
* Sets the component author.
*
* @since 4.7.6
*
* @return void
*/
private function setAuthor() {
switch ( $this->templateType ) {
case 'bp-activity_single':
if ( ! $this->activity ) {
$this->setActivity();
}
if ( $this->activity ) {
$this->author = get_user_by( 'id', $this->activity['user_id'] );
return;
}
break;
case 'bp-group_single':
if ( ! $this->group ) {
$this->setGroup();
}
if ( $this->group ) {
$this->author = get_user_by( 'id', $this->group['creator_id'] );
return;
}
break;
case 'bp-member_single':
$this->author = get_user_by( 'slug', $this->id );
return;
}
}
/**
* Sets the component date.
*
* @since 4.7.6
*
* @return void
*/
private function setDate() {
switch ( $this->templateType ) {
case 'bp-activity_single':
if ( ! $this->activity ) {
$this->setActivity();
}
$date = strtotime( $this->activity['date_recorded'] );
break;
case 'bp-group_single':
if ( ! $this->group ) {
$this->setGroup();
}
$date = strtotime( $this->group['date_created'] );
break;
default:
$date = $this->date;
}
$this->date = $date;
}
/**
* Sets the activity data.
*
* @since 4.7.6
*
* @return void
*/
private function setActivity() {
if ( 'bp-activity_single' !== $this->templateType ) {
return;
}
$activities = BuddyPressIntegration::callFunc( 'bp_activity_get_specific', [
'activity_ids' => [ $this->id ],
'display_comments' => true
] );
if ( ! empty( $activities['activities'] ) ) {
list( $activity ) = current( $activities );
$this->activity = (array) $activity;
// The `content_rendered` is AIOSEO specific.
$this->activity['content_rendered'] = $this->activity['content'] ?? '';
if ( ! empty( $this->activity['content'] ) ) {
$this->activity['content_rendered'] = apply_filters( 'bp_get_activity_content', $this->activity['content'] );
}
return;
}
$this->resetComponent();
}
/**
* Sets the group data.
*
* @since 4.7.6
*
* @return void
*/
private function setGroup() {
if ( 'bp-group_single' !== $this->templateType ) {
return;
}
$group = BuddyPressIntegration::callFunc( 'bp_get_group_by', 'slug', $this->id );
if ( ! empty( $group ) ) {
$this->group = (array) $group;
return;
}
$this->resetComponent();
}
/**
* Sets the group type.
*
* @since 4.7.6
*
* @return void
*/
private function setGroupType() {
if ( 'bp-group_archive' !== $this->templateType ) {
return;
}
$type = BuddyPressIntegration::callFunc( 'bp_get_current_group_directory_type' );
if ( ! $type ) {
return;
}
$term = get_term_by( 'slug', $type, 'bp_group_type' );
if ( ! $term ) {
return;
}
$meta = get_metadata( 'term', $term->term_id );
if ( ! $meta ) {
return;
}
$this->groupType = [
'singular' => $meta['bp_type_singular_name'][0] ?? '',
'plural' => $meta['bp_type_name'][0] ?? '',
];
}
/**
* Resets some of the component properties.
*
* @since 4.7.6
*
* @return void
*/
private function resetComponent() {
$this->templateType = null;
$this->id = 0;
}
/**
* Retrieves the SEO metadata value.
*
* @since 4.7.6
*
* @param string $which The SEO metadata to get.
* @return string The SEO metadata value.
*/
public function getMeta( $which ) {
list( $postType, $suffix ) = explode( '_', $this->templateType );
switch ( $which ) {
case 'title':
$meta = 'single' === $suffix
? aioseo()->meta->title->getPostTypeTitle( $postType )
: aioseo()->meta->title->getArchiveTitle( $postType );
$meta = aioseo()->meta->description->helpers->bpSanitize( $meta, $this->id );
break;
case 'description':
$meta = 'single' === $suffix
? aioseo()->meta->description->getPostTypeDescription( $postType )
: aioseo()->meta->description->getArchiveDescription( $postType );
$meta = aioseo()->meta->description->helpers->bpSanitize( $meta, $this->id );
break;
case 'keywords':
$meta = 'single' === $suffix
? ''
: aioseo()->meta->keywords->getArchiveKeywords( $postType );
$meta = aioseo()->meta->keywords->prepareKeywords( $meta );
break;
case 'robots':
$dynamicOptions = aioseo()->dynamicOptions->noConflict();
if ( 'single' === $suffix && $dynamicOptions->searchAppearance->postTypes->has( $postType ) ) {
aioseo()->meta->robots->globalValues( [ 'postTypes', $postType ], true );
} elseif ( $dynamicOptions->searchAppearance->archives->has( $postType ) ) {
aioseo()->meta->robots->globalValues( [ 'archives', $postType ], true );
}
$meta = aioseo()->meta->robots->metaHelper();
break;
case 'canonical':
$meta = '';
if ( 'single' === $suffix ) {
if ( 'bp-member' === $postType ) {
$meta = BuddyPressIntegration::getComponentSingleUrl( 'member', $this->author->ID );
} elseif ( 'bp-group' === $postType ) {
$meta = BuddyPressIntegration::getComponentSingleUrl( 'group', $this->group['id'] );
}
}
break;
default:
$meta = '';
}
return $meta;
}
/**
* Determines the schema type for the current component.
*
* @since 4.7.6
*
* @param \AIOSEO\Plugin\Common\Schema\Context $contextInstance The Context class instance.
* @return void
*/
public function determineSchemaGraphsAndContext( $contextInstance ) {
list( $postType ) = explode( '_', $this->templateType );
$dynamicOptions = aioseo()->dynamicOptions->noConflict();
if ( $dynamicOptions->searchAppearance->postTypes->has( $postType ) ) {
$defaultType = $dynamicOptions->searchAppearance->postTypes->{$postType}->schemaType;
switch ( $defaultType ) {
case 'Article':
aioseo()->schema->graphs[] = $dynamicOptions->searchAppearance->postTypes->{$postType}->articleType;
break;
case 'WebPage':
aioseo()->schema->graphs[] = $dynamicOptions->searchAppearance->postTypes->{$postType}->webPageType;
break;
default:
aioseo()->schema->graphs[] = $defaultType;
}
}
switch ( $this->templateType ) {
case 'bp-activity_single':
$datePublished = $this->activity['date_recorded'];
$contextUrl = BuddyPressIntegration::getComponentSingleUrl( 'activity', $this->activity['id'] );
break;
case 'bp-group_single':
$datePublished = $this->group['date_created'];
$contextUrl = BuddyPressIntegration::getComponentSingleUrl( 'group', $this->group['id'] );
break;
case 'bp-member_single':
aioseo()->schema->graphs[] = 'ProfilePage';
$contextUrl = BuddyPressIntegration::getComponentSingleUrl( 'member', $this->author->ID );
break;
case 'bp-activity_archive':
case 'bp-group_archive':
case 'bp-member_archive':
list( , $component ) = explode( '-', $postType );
$contextUrl = BuddyPressIntegration::getComponentArchiveUrl( $component );
$breadcrumbType = 'CollectionPage';
break;
default:
break;
}
if ( ! empty( $datePublished ) ) {
CommonGraphs\Article\NewsArticle::setOverwriteGraphData( [
'properties' => compact( 'datePublished' )
] );
}
if ( ! empty( $contextUrl ) ) {
$name = aioseo()->meta->title->getTitle();
$description = aioseo()->meta->description->getDescription();
$breadcrumbPositions = [
'name' => $name,
'description' => $description,
'url' => $contextUrl,
];
if ( ! empty( $breadcrumbType ) ) {
$breadcrumbPositions['type'] = $breadcrumbType;
}
aioseo()->schema->context = [
'name' => $name,
'description' => $description,
'url' => $contextUrl,
'breadcrumb' => $contextInstance->breadcrumb->setPositions( $breadcrumbPositions ),
];
}
}
/**
* Gets the breadcrumbs for the current component.
*
* @since 4.7.6
*
* @return array
*/
public function getCrumbs() {
$crumbs = [];
switch ( $this->templateType ) {
case 'bp-activity_single':
$crumbs[] = aioseo()->breadcrumbs->makeCrumb(
BuddyPressIntegration::callFunc( 'bp_get_directory_title', 'activity' ),
BuddyPressIntegration::getComponentArchiveUrl( 'activity' )
);
$crumbs[] = aioseo()->breadcrumbs->makeCrumb( sanitize_text_field( $this->activity['action'] ) );
break;
case 'bp-group_single':
$crumbs[] = aioseo()->breadcrumbs->makeCrumb(
BuddyPressIntegration::callFunc( 'bp_get_directory_title', 'groups' ),
BuddyPressIntegration::getComponentArchiveUrl( 'group' )
);
$crumbs[] = aioseo()->breadcrumbs->makeCrumb( $this->group['name'] );
break;
case 'bp-member_single':
$crumbs[] = aioseo()->breadcrumbs->makeCrumb(
BuddyPressIntegration::callFunc( 'bp_get_directory_title', 'members' ),
BuddyPressIntegration::getComponentArchiveUrl( 'member' )
);
$crumbs[] = aioseo()->breadcrumbs->makeCrumb( $this->author->display_name );
break;
case 'bp-activity_archive':
$crumbs[] = aioseo()->breadcrumbs->makeCrumb( BuddyPressIntegration::callFunc( 'bp_get_directory_title', 'activity' ) );
break;
case 'bp-group_archive':
$crumbs[] = aioseo()->breadcrumbs->makeCrumb( BuddyPressIntegration::callFunc( 'bp_get_directory_title', 'groups' ) );
break;
case 'bp-member_archive':
$crumbs[] = aioseo()->breadcrumbs->makeCrumb( BuddyPressIntegration::callFunc( 'bp_get_directory_title', 'members' ) );
break;
default:
break;
}
return $crumbs;
}
} BuddyPress/BuddyPress.php 0000666 00000023313 15114751622 0011437 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\BuddyPress;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Integrations\BuddyPress as BuddyPressIntegration;
/**
* Handles the BuddyPress integration with AIOSEO.
*
* @since 4.7.6
*/
class BuddyPress {
/**
* Instance of the Tags class.
*
* @since 4.7.6
*
* @var Tags
*/
public $tags;
/**
* Instance of the Component class.
*
* @since 4.7.6
*
* @var Component
*/
public $component;
/**
* Instance of the Sitemap class.
*
* @since 4.7.6
*
* @var Sitemap
*/
public $sitemap = null;
/**
* Class constructor.
*
* @since 4.7.6
*/
public function __construct() {
if (
aioseo()->helpers->isAjaxCronRestRequest() ||
! aioseo()->helpers->isPluginActive( 'buddypress' )
) {
return;
}
// Hook into `plugins_loaded` to ensure BuddyPress has loaded some necessary functions.
add_action( 'plugins_loaded', [ $this, 'maybeLoad' ], 20 );
}
/**
* Hooked into `plugins_loaded` action hook.
*
* @since 4.7.6
*
* @return void
*/
public function maybeLoad() {
// If the BuddyPress version is below 12 we bail.
if ( ! function_exists( 'bp_get_version' ) || version_compare( bp_get_version(), '12', '<' ) ) {
return;
}
// If none of the necessary BuddyPress components are active we bail.
if (
! BuddyPressIntegration::isComponentActive( 'activity' ) &&
! BuddyPressIntegration::isComponentActive( 'group' ) &&
! BuddyPressIntegration::isComponentActive( 'member' )
) {
return;
}
$this->sitemap = new Sitemap();
add_action( 'init', [ $this, 'setTags' ], 20 );
add_action( 'bp_parse_query', [ $this, 'setComponent' ], 20 );
}
/**
* Hooked into `init` action hook.
*
* @since 4.7.6
*
* @return void
*/
public function setTags() {
$this->tags = new Tags();
}
/**
* Hooked into `bp_parse_query` action hook.
*
* @since 4.7.6
*
* @return void
*/
public function setComponent() {
$this->component = new Component();
}
/**
* Adds the BuddyPress fake post types to the list of post types, so they appear under e.g. Search Appearance.
*
* @since 4.7.6
*
* @param array $postTypes Public post types from {@see \AIOSEO\Plugin\Common\Traits\Helpers\Wp::getPublicPostTypes}.
* @param bool $namesOnly Whether only the names should be included.
* @param bool $hasArchivesOnly Whether to only include post types which have archives.
* @param array $args Additional arguments.
* @return void
*/
public function maybeAddPostTypes( &$postTypes, $namesOnly, $hasArchivesOnly, $args ) {
// If one of these CPTs is already registered we bail, so we don't overwrite them and possibly break something.
if (
post_type_exists( 'bp-activity' ) ||
post_type_exists( 'bp-group' ) ||
post_type_exists( 'bp-member' )
) {
return;
}
/**
* The BP components are registered with the `buddypress` CPT which is not viewable, so we add it here to include our metadata inside <head>.
* {@see \AIOSEO\Plugin\Common\Main\Head::wpHead}.
*/
if (
$namesOnly &&
doing_action( 'wp_head' )
) {
$postTypes = array_merge( $postTypes, [ 'buddypress' ] );
return;
}
$fakePostTypes = $this->getFakePostTypes();
if ( ! BuddyPressIntegration::isComponentActive( 'activity' ) ) {
unset( $fakePostTypes['bp-activity'] );
}
if ( ! BuddyPressIntegration::isComponentActive( 'group' ) ) {
unset( $fakePostTypes['bp-group'] );
}
if ( ! BuddyPressIntegration::isComponentActive( 'member' ) ) {
unset( $fakePostTypes['bp-member'] );
}
if ( $hasArchivesOnly ) {
$fakePostTypes = array_filter( $fakePostTypes, function ( $postType ) {
return $postType['hasArchive'];
} );
}
if ( $namesOnly ) {
$fakePostTypes = array_keys( $fakePostTypes );
}
// 0. Below we'll add/merge the BuddyPress post types only under certain conditions.
$fakePostTypes = array_values( $fakePostTypes );
$currentScreen = aioseo()->helpers->getCurrentScreen();
if (
// 1. If the `buddypress` CPT is set in the list of post types to be included.
( ! empty( $args['include'] ) && in_array( 'buddypress', $args['include'], true ) ) ||
// 2. If the current request is for the sitemap.
( ! empty( aioseo()->sitemap->filename ) && 'general' === ( aioseo()->sitemap->type ?? '' ) ) ||
// 3. If we're on the Search Appearance screen.
( $currentScreen && strpos( $currentScreen->id, 'aioseo-search-appearance' ) !== false ) ||
// 4. If we're on the BuddyPress component front-end screen.
BuddyPressIntegration::isComponentPage()
) {
$postTypes = array_merge( $postTypes, $fakePostTypes );
}
}
/**
* Get edit links for the SEO Preview data.
*
* @since 4.7.6
*
* @return array
*/
public function getVueDataSeoPreview() {
$data = [
'editGoogleSnippetUrl' => '',
'editObjectBtnText' => '',
'editObjectUrl' => '',
];
list( $postType, $suffix ) = explode( '_', aioseo()->standalone->buddyPress->component->templateType );
$bpFakePostTypes = $this->getFakePostTypes();
$fakePostTypeData = array_values( wp_list_filter( $bpFakePostTypes, [ 'name' => $postType ] ) );
$fakePostTypeData = $fakePostTypeData[0] ?? [];
if ( ! $fakePostTypeData ) {
return $data;
}
if ( 'single' === $suffix ) {
switch ( $postType ) {
case 'bp-activity':
$componentId = aioseo()->standalone->buddyPress->component->activity['id'];
break;
case 'bp-group':
$componentId = aioseo()->standalone->buddyPress->component->group['id'];
break;
case 'bp-member':
$componentId = aioseo()->standalone->buddyPress->component->author->ID;
break;
default:
$componentId = 0;
}
}
$scrollToId = 'aioseo-card-' . $postType . ( 'single' === $suffix ? 'SA' : 'ArchiveArchives' );
$data['editGoogleSnippetUrl'] = 'single' === $suffix
? admin_url( 'admin.php?page=aioseo-search-appearance' ) . '#/content-types'
: admin_url( 'admin.php?page=aioseo-search-appearance' ) . '#/archives';
$data['editGoogleSnippetUrl'] = add_query_arg( [
'aioseo-scroll' => $scrollToId,
'aioseo-highlight' => $scrollToId
], $data['editGoogleSnippetUrl'] );
$data['editObjectBtnText'] = sprintf(
// Translators: 1 - A noun for something that's being edited ("Post", "Page", "Article", "Product", etc.).
esc_html__( 'Edit %1$s', 'all-in-one-seo-pack' ),
'single' === $suffix ? $fakePostTypeData['singular'] : $fakePostTypeData['label']
);
list( , $component ) = explode( '-', $postType );
$data['editObjectUrl'] = 'single' === $suffix
? BuddyPressIntegration::getComponentEditUrl( $component, $componentId ?? 0 )
: BuddyPressIntegration::callFunc( 'bp_get_admin_url', add_query_arg( 'page', 'bp-rewrites', 'admin.php' ) );
return $data;
}
/**
* Retrieves the BuddyPress fake post types.
*
* @since 4.7.6
*
* @return array The BuddyPress fake post types.
*/
public function getFakePostTypes() {
return [
'bp-activity' => [
'name' => 'bp-activity',
'label' => sprintf(
// Translators: 1 - The hard coded string 'BuddyPress'.
_x( 'Activities (%1$s)', 'BuddyPress', 'all-in-one-seo-pack' ),
'BuddyPress'
),
'singular' => 'Activity',
'icon' => 'dashicons-buddicons-buddypress-logo',
'hasExcerpt' => false,
'hasArchive' => true,
'hierarchical' => false,
'taxonomies' => [],
'slug' => 'bp-activity',
'buddyPress' => true,
'defaultTags' => [
'postTypes' => [
'title' => [
'bp_activity_action',
'separator_sa',
'site_title',
],
'description' => [
'bp_activity_content',
'separator_sa'
]
]
],
'defaultTitle' => '#bp_activity_action #separator_sa #site_title',
'defaultDescription' => '#bp_activity_content',
],
'bp-group' => [
'name' => 'bp-group',
'label' => sprintf(
// Translators: 1 - The hard coded string 'BuddyPress'.
_x( 'Groups (%1$s)', 'BuddyPress', 'all-in-one-seo-pack' ),
'BuddyPress'
),
'singular' => 'Group',
'icon' => 'dashicons-buddicons-buddypress-logo',
'hasExcerpt' => false,
'hasArchive' => true,
'hierarchical' => false,
'taxonomies' => [],
'slug' => 'bp-group',
'buddyPress' => true,
'defaultTags' => [
'postTypes' => [
'title' => [
'bp_group_name',
'separator_sa',
'site_title',
],
'description' => [
'bp_group_description',
'separator_sa'
]
]
],
'defaultTitle' => '#bp_group_name #separator_sa #site_title',
'defaultDescription' => '#bp_group_description',
],
'bp-member' => [
'name' => 'bp-member',
'label' => sprintf(
// Translators: 1 - The hard coded string 'BuddyPress'.
_x( 'Members (%1$s)', 'BuddyPress', 'all-in-one-seo-pack' ),
'BuddyPress'
),
'singular' => 'Member',
'icon' => 'dashicons-buddicons-buddypress-logo',
'hasExcerpt' => false,
'hasArchive' => true,
'hierarchical' => false,
'taxonomies' => [],
'slug' => 'bp-member',
'buddyPress' => true,
'defaultTags' => [
'postTypes' => [
'title' => [
'author_name',
'separator_sa',
'site_title',
],
'description' => [
'author_bio',
'separator_sa'
]
]
],
'defaultTitle' => '#author_name #separator_sa #site_title',
'defaultDescription' => '#author_bio',
],
];
}
} BuddyPress/Tags.php 0000666 00000023531 15114751622 0010253 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\BuddyPress;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* BuddyPress Tags class.
*
* @since 4.7.6
*/
class Tags {
/**
* Class constructor.
*
* @since 4.7.6
*/
public function __construct() {
aioseo()->tags->addContext( $this->getContexts() );
aioseo()->tags->addTags( $this->getTags() );
}
/**
* Retrieves the contexts for BuddyPress.
*
* @since 4.7.6
*
* @return array An array of contextual data.
*/
public function getContexts() {
return [
'bp-activityTitle' => [
'author_first_name',
'author_last_name',
'author_name',
'current_date',
'current_day',
'current_month',
'current_year',
'post_date',
'post_day',
'post_month',
'post_year',
'separator_sa',
'site_title',
'tagline',
'bp_activity_action',
'bp_activity_content',
],
'bp-activityArchiveTitle' => [
'current_date',
'current_day',
'current_month',
'current_year',
'separator_sa',
'site_title',
'tagline',
'archive_title',
],
'bp-activityDescription' => [
'author_first_name',
'author_last_name',
'author_name',
'current_date',
'current_day',
'current_month',
'current_year',
'post_date',
'post_day',
'post_month',
'post_year',
'separator_sa',
'site_title',
'tagline',
'bp_activity_action',
'bp_activity_content',
],
'bp-activityArchiveDescription' => [
'current_date',
'current_day',
'current_month',
'current_year',
'separator_sa',
'site_title',
'tagline',
'archive_title',
],
'bp-groupTitle' => [
'author_first_name',
'author_last_name',
'author_name',
'current_date',
'current_day',
'current_month',
'current_year',
'post_date',
'post_day',
'post_month',
'post_year',
'separator_sa',
'site_title',
'tagline',
'bp_group_name',
'bp_group_description',
],
'bp-groupArchiveTitle' => [
'current_date',
'current_day',
'current_month',
'current_year',
'separator_sa',
'site_title',
'tagline',
'archive_title',
'bp_group_type_singular_name',
'bp_group_type_plural_name',
],
'bp-groupDescription' => [
'author_first_name',
'author_last_name',
'author_name',
'current_date',
'current_day',
'current_month',
'current_year',
'post_date',
'post_day',
'post_month',
'post_year',
'separator_sa',
'site_title',
'tagline',
'bp_group_name',
'bp_group_description',
],
'bp-groupArchiveDescription' => [
'current_date',
'current_day',
'current_month',
'current_year',
'separator_sa',
'site_title',
'tagline',
'archive_title',
'bp_group_type_singular_name',
'bp_group_type_plural_name',
],
'bp-memberTitle' => [
'author_first_name',
'author_last_name',
'author_name',
'current_date',
'current_day',
'current_month',
'current_year',
'separator_sa',
'site_title',
'tagline',
],
'bp-memberArchiveTitle' => [
'current_date',
'current_day',
'current_month',
'current_year',
'separator_sa',
'site_title',
'tagline',
'archive_title',
],
'bp-memberDescription' => [
'author_first_name',
'author_last_name',
'author_name',
'author_bio',
'current_date',
'current_day',
'current_month',
'current_year',
'separator_sa',
'site_title',
'tagline',
],
'bp-memberArchiveDescription' => [
'current_date',
'current_day',
'current_month',
'current_year',
'separator_sa',
'site_title',
'tagline',
'archive_title',
],
];
}
/**
* Retrieves the custom tags for BuddyPress.
*
* @since 4.7.6
*
* @return array An array of tags.
*/
public function getTags() {
return [
[
'id' => 'bp_activity_action',
'name' => _x( 'Activity Action', 'BuddyPress', 'all-in-one-seo-pack' ),
'description' => _x( 'The activity action.', 'BuddyPress', 'all-in-one-seo-pack' ),
'instance' => $this,
],
[
'id' => 'bp_activity_content',
'name' => _x( 'Activity Content', 'BuddyPress', 'all-in-one-seo-pack' ),
'description' => _x( 'The activity content.', 'BuddyPress', 'all-in-one-seo-pack' ),
'instance' => $this,
],
[
'id' => 'bp_group_name',
'name' => _x( 'Group Name', 'BuddyPress', 'all-in-one-seo-pack' ),
'description' => _x( 'The group name.', 'BuddyPress', 'all-in-one-seo-pack' ),
'instance' => $this,
],
[
'id' => 'bp_group_description',
'name' => _x( 'Group Description', 'BuddyPress', 'all-in-one-seo-pack' ),
'description' => _x( 'The group description.', 'BuddyPress', 'all-in-one-seo-pack' ),
'instance' => $this,
],
[
'id' => 'bp_group_type_singular_name',
'name' => _x( 'Group Type Singular Name', 'BuddyPress', 'all-in-one-seo-pack' ),
'description' => _x( 'The group type singular name.', 'BuddyPress', 'all-in-one-seo-pack' ),
'instance' => $this,
],
[
'id' => 'bp_group_type_plural_name',
'name' => _x( 'Group Type Plural Name', 'BuddyPress', 'all-in-one-seo-pack' ),
'description' => _x( 'The group type plural name.', 'BuddyPress', 'all-in-one-seo-pack' ),
'instance' => $this,
],
];
}
/**
* Replace the tags in the string provided.
*
* @since 4.7.6
*
* @param string $string The string to look for tags in.
* @param int $id The object ID.
* @return string The string with tags replaced.
*/
public function replaceTags( $string, $id ) {
if ( ! $string || ! preg_match( '/' . aioseo()->tags->denotationChar . '/', $string ) ) {
return $string;
}
foreach ( array_unique( aioseo()->helpers->flatten( $this->getContexts() ) ) as $tag ) {
$tagId = aioseo()->tags->denotationChar . $tag;
$pattern = "/$tagId(?![a-zA-Z0-9_])/im";
if ( preg_match( $pattern, $string ) ) {
$tagValue = $this->getTagValue( [ 'id' => $tag ], $id );
$string = preg_replace( $pattern, '%|%' . aioseo()->helpers->escapeRegexReplacement( $tagValue ), $string );
}
}
return str_replace( '%|%', '', $string );
}
/**
* Get the value of the tag to replace.
*
* @since 4.7.6
*
* @param array $tag The tag to look for.
* @param int|null $id The object ID.
* @param bool $sampleData Whether to fill empty values with sample data.
* @return string The value of the tag.
*/
public function getTagValue( $tag, $id = null, $sampleData = false ) {
$sampleData = $sampleData || empty( aioseo()->standalone->buddyPress->component->templateType );
switch ( $tag['id'] ) {
case 'author_bio':
$out = $sampleData
? __( 'Sample author biography', 'all-in-one-seo-pack' )
: aioseo()->standalone->buddyPress->component->author->description;
break;
case 'author_first_name':
$out = $sampleData
? wp_get_current_user()->first_name
: aioseo()->standalone->buddyPress->component->author->first_name;
break;
case 'author_last_name':
$out = $sampleData
? wp_get_current_user()->last_name
: aioseo()->standalone->buddyPress->component->author->last_name;
break;
case 'author_name':
$out = $sampleData
? wp_get_current_user()->display_name
: aioseo()->standalone->buddyPress->component->author->display_name;
break;
case 'post_date':
$out = $sampleData
? aioseo()->tags->formatDateAsI18n( date_i18n( 'U' ) )
: aioseo()->tags->formatDateAsI18n( aioseo()->standalone->buddyPress->component->date );
break;
case 'post_day':
$out = $sampleData
? date_i18n( 'd' )
: date( 'd', aioseo()->standalone->buddyPress->component->date );
break;
case 'post_month':
$out = $sampleData
? date_i18n( 'F' )
: date( 'F', aioseo()->standalone->buddyPress->component->date );
break;
case 'post_year':
$out = $sampleData
? date_i18n( 'Y' )
: date( 'Y', aioseo()->standalone->buddyPress->component->date );
break;
case 'archive_title':
$out = $sampleData
? __( 'Sample Archive Title', 'all-in-one-seo-pack' )
: esc_html( get_the_title() );
break;
case 'bp_activity_action':
$out = $sampleData
? _x( 'Sample Activity Action', 'BuddyPress', 'all-in-one-seo-pack' )
: aioseo()->standalone->buddyPress->component->activity['action'];
break;
case 'bp_activity_content':
$out = $sampleData
? _x( 'Sample activity content', 'BuddyPress', 'all-in-one-seo-pack' )
: aioseo()->standalone->buddyPress->component->activity['content_rendered'];
break;
case 'bp_group_name':
$out = $sampleData
? _x( 'Sample Group Name', 'BuddyPress', 'all-in-one-seo-pack' )
: aioseo()->standalone->buddyPress->component->group['name'];
break;
case 'bp_group_description':
$out = $sampleData
? _x( 'Sample group description', 'BuddyPress', 'all-in-one-seo-pack' )
: aioseo()->standalone->buddyPress->component->group['description'];
break;
case 'bp_group_type_singular_name':
$out = $sampleData ? _x( 'Sample Type Singular', 'BuddyPress', 'all-in-one-seo-pack' ) : '';
if ( ! empty( aioseo()->standalone->buddyPress->component->groupType ) ) {
$out = aioseo()->standalone->buddyPress->component->groupType['singular'];
}
break;
case 'bp_group_type_plural_name':
$out = $sampleData ? _x( 'Sample Type Plural', 'BuddyPress', 'all-in-one-seo-pack' ) : '';
if ( ! empty( aioseo()->standalone->buddyPress->component->groupType ) ) {
$out = aioseo()->standalone->buddyPress->component->groupType['plural'];
}
break;
default:
$out = aioseo()->tags->getTagValue( $tag, $id );
}
return $out ?? '';
}
} DetailsColumn.php 0000666 00000020310 15114751622 0010024 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* Handles the AIOSEO Details post column.
*
* @since 4.2.0
*/
class DetailsColumn {
/**
* The slug for the script.
*
* @since 4.2.0
*
* @var string
*/
protected $scriptSlug = 'src/vue/standalone/posts-table/main.js';
/**
* Class constructor.
*
* @since 4.2.0
*/
public function __construct() {
if ( wp_doing_ajax() ) {
add_action( 'init', [ $this, 'addPostColumnsAjax' ], 1 );
}
if ( ! is_admin() || wp_doing_cron() ) {
return;
}
add_action( 'current_screen', [ $this, 'registerColumnHooks' ], 1 );
}
/**
* Adds the columns to the page/post types.
*
* @since 4.0.0
*
* @return void
*/
public function registerColumnHooks() {
$screen = aioseo()->helpers->getCurrentScreen();
if ( empty( $screen->base ) || empty( $screen->post_type ) ) {
return;
}
if ( ! $this->shouldRegisterColumn( $screen->base, $screen->post_type ) ) {
return;
}
add_action( 'admin_enqueue_scripts', [ $this, 'enqueueScripts' ] );
if ( 'product' === $screen->post_type ) {
add_filter( 'manage_edit-product_columns', [ $this, 'addColumn' ] );
add_action( 'manage_posts_custom_column', [ $this, 'renderColumn' ], 10, 2 );
return;
}
if ( 'attachment' === $screen->post_type ) {
$enabled = apply_filters( 'aioseo_image_seo_media_columns', true );
if ( ! $enabled ) {
return;
}
add_filter( 'manage_media_columns', [ $this, 'addColumn' ] );
add_action( 'manage_media_custom_column', [ $this, 'renderColumn' ], 10, 2 );
return;
}
add_filter( "manage_edit-{$screen->post_type}_columns", [ $this, 'addColumn' ] );
add_action( "manage_{$screen->post_type}_posts_custom_column", [ $this, 'renderColumn' ], 10, 2 );
}
/**
* Registers our post columns after a post has been quick-edited.
*
* @since 4.2.3
*
* @return void
*/
public function addPostColumnsAjax() {
if (
! isset( $_POST['_inline_edit'], $_POST['post_ID'], $_POST['aioseo-has-details-column'] ) ||
! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_inline_edit'] ) ), 'inlineeditnonce' )
) {
return;
}
$postId = (int) $_POST['post_ID'];
if ( ! $postId ) {
return;
}
$post = get_post( $postId );
$postType = $post->post_type;
add_filter( "manage_edit-{$postType}_columns", [ $this, 'addColumn' ] );
add_action( "manage_{$postType}_posts_custom_column", [ $this, 'renderColumn' ], 10, 2 );
}
/**
* Enqueues the JS/CSS for the page/posts table page.
*
* @since 4.0.0
*
* @return void
*/
public function enqueueScripts() {
$data = aioseo()->helpers->getVueData();
$data['posts'] = [];
$data['terms'] = [];
aioseo()->core->assets->load( $this->scriptSlug, [], $data );
}
/**
* Adds the AIOSEO Details column to the page/post tables in the admin.
*
* @since 4.0.0
*
* @param array $columns The columns we are adding ours onto.
* @return array The modified columns.
*/
public function addColumn( $columns ) {
$canManageSeo = apply_filters( 'aioseo_manage_seo', 'aioseo_manage_seo' );
if (
! current_user_can( $canManageSeo ) &&
(
! current_user_can( 'aioseo_page_general_settings' ) &&
! current_user_can( 'aioseo_page_analysis' )
)
) {
return $columns;
}
// Translators: 1 - The short plugin name ("AIOSEO").
$columns['aioseo-details'] = sprintf( esc_html__( '%1$s Details', 'all-in-one-seo-pack' ), AIOSEO_PLUGIN_SHORT_NAME );
return $columns;
}
/**
* Renders the column in the page/post table.
*
* @since 4.0.0
*
* @param string $columnName The column name.
* @param int $postId The current rows, post id.
* @return void
*/
public function renderColumn( $columnName, $postId = 0 ) {
if ( ! current_user_can( 'edit_post', $postId ) && ! current_user_can( 'aioseo_manage_seo' ) ) {
return;
}
if ( 'aioseo-details' !== $columnName ) {
return;
}
// Add this column/post to the localized array.
global $wp_scripts; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
if (
! is_object( $wp_scripts ) || // phpcs:ignore Squiz.NamingConventions.ValidVariableName
! method_exists( $wp_scripts, 'get_data' ) || // phpcs:ignore Squiz.NamingConventions.ValidVariableName
! method_exists( $wp_scripts, 'add_data' ) // phpcs:ignore Squiz.NamingConventions.ValidVariableName
) {
return;
}
$data = null;
if ( is_object( $wp_scripts ) ) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$data = $wp_scripts->get_data( 'aioseo/js/' . $this->scriptSlug, 'data' ); // phpcs:ignore Squiz.NamingConventions.ValidVariableName
}
if ( ! is_array( $data ) ) {
$data = json_decode( str_replace( 'var aioseo = ', '', substr( $data, 0, -1 ) ), true );
}
// We have to temporarily modify the query here since the query incorrectly identifies
// the current page as a category page when posts are filtered by a specific category.
// phpcs:disable Squiz.NamingConventions.ValidVariableName
global $wp_query;
$originalQuery = clone $wp_query;
$wp_query->is_category = false;
$wp_query->is_tag = false;
$wp_query->is_tax = false;
// phpcs:enable Squiz.NamingConventions.ValidVariableName
$posts = ! empty( $data['posts'] ) ? $data['posts'] : [];
$postData = $this->getPostData( $postId, $columnName );
$addonsColumnData = array_filter( aioseo()->addons->doAddonFunction( 'admin', 'renderColumnData', [
$columnName,
$postId,
$postData
] ) );
$wp_query = $originalQuery; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
foreach ( $addonsColumnData as $addonColumnData ) {
$postData = array_merge( $postData, $addonColumnData );
}
$posts[] = $postData;
$data['posts'] = $posts;
$wp_scripts->add_data( 'aioseo/js/' . $this->scriptSlug, 'data', '' ); // phpcs:ignore Squiz.NamingConventions.ValidVariableName
wp_localize_script( 'aioseo/js/' . $this->scriptSlug, 'aioseo', $data );
require AIOSEO_DIR . '/app/Common/Views/admin/posts/columns.php';
}
/**
* Gets the post data for the column.
*
* @since 4.5.0
*
* @param int $postId The Post ID.
* @param string $columnName The column name.
* @return array The post data.
*/
protected function getPostData( $postId, $columnName ) {
$nonce = wp_create_nonce( "aioseo_meta_{$columnName}_{$postId}" );
$thePost = Models\Post::getPost( $postId );
$postType = get_post_type( $postId );
$postData = [
'id' => $postId,
'columnName' => $columnName,
'nonce' => $nonce,
'title' => $thePost->title,
'defaultTitle' => aioseo()->meta->title->getPostTypeTitle( $postType ),
'showTitle' => apply_filters( 'aioseo_details_column_post_show_title', true, $postId ),
'description' => $thePost->description,
'defaultDescription' => aioseo()->meta->description->getPostTypeDescription( $postType ),
'showDescription' => apply_filters( 'aioseo_details_column_post_show_description', true, $postId ),
'value' => ! empty( $thePost->seo_score ) ? (int) $thePost->seo_score : 0,
'showMedia' => false,
'isSpecialPage' => aioseo()->helpers->isSpecialPage( $postId ),
'postType' => $postType,
'isPostVisible' => aioseo()->helpers->isPostPubliclyViewable( $postId )
];
return $postData;
}
/**
* Checks whether the AIOSEO Details column should be registered.
*
* @since 4.0.0
*
* @return bool Whether the column should be registered.
*/
public function shouldRegisterColumn( $screen, $postType ) {
// Only allow users with the correct permissions to see the column.
if ( ! current_user_can( 'aioseo_page_general_settings' ) ) {
return false;
}
if ( 'type' === $postType ) {
$postType = '_aioseo_type';
}
if ( 'edit' === $screen || 'upload' === $screen ) {
if (
aioseo()->options->advanced->postTypes->all &&
in_array( $postType, aioseo()->helpers->getPublicPostTypes( true ), true )
) {
return true;
}
$postTypes = aioseo()->options->advanced->postTypes->included;
if ( in_array( $postType, $postTypes, true ) ) {
return true;
}
}
return false;
}
} WpCode.php 0000666 00000001354 15114751622 0006451 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles registering the AIOSEO username in the WPCode snippets library.
*
* @since 4.3.8
*/
class WpCode {
/**
* Class constructor.
*
* @since 4.3.8
*/
public function __construct() {
if ( ! is_admin() || wp_doing_ajax() || wp_doing_cron() ) {
return;
}
add_action( 'wpcode_loaded', [ $this, 'registerUsername' ] );
}
/**
* Enqueues the script.
*
* @since 4.3.8
*
* @return void
*/
public function registerUsername() {
if ( ! function_exists( 'wpcode_register_library_username' ) ) {
return;
}
wpcode_register_library_username( 'aioseo', AIOSEO_PLUGIN_SHORT_NAME );
}
} LimitModifiedDate.php 0000666 00000016355 15114751622 0010614 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* Limit Modified Date class.
*
* @since 4.1.8
*/
class LimitModifiedDate {
/**
* Class constructor.
*
* @since 4.1.8
*
* @return void
*/
public function __construct() {
if ( apply_filters( 'aioseo_last_modified_date_disable', false ) ) {
return;
}
// Reset modified date when the post is updated.
add_filter( 'wp_insert_post_data', [ $this, 'resetModifiedDate' ], 99999, 2 );
add_filter( 'wp_insert_attachment_data', [ $this, 'resetModifiedDate' ], 99999, 2 );
add_action( 'woocommerce_before_product_object_save', [ $this, 'limitWooCommerceModifiedDate' ] );
add_action( 'rest_api_init', [ $this, 'registerRestHooks' ] );
if ( ! is_admin() ) {
return;
}
add_action( 'admin_enqueue_scripts', [ $this, 'enqueueScripts' ], 20 );
add_action( 'post_submitbox_misc_actions', [ $this, 'classicEditorField' ] );
}
/**
* Register the REST API hooks.
*
* @since 4.1.8
*
* @return void
*/
public function registerRestHooks() {
// Prevent REST API from dropping limit modified date value before updating the post.
foreach ( aioseo()->helpers->getPublicPostTypes( true ) as $postType ) {
add_filter( "rest_pre_insert_$postType", [ $this, 'addLimitModifiedDateValue' ], 10, 2 );
}
}
/**
* Enqueues the scripts for the Limited Modified Date functionality.
*
* @since 4.1.8
*
* @return void
*/
public function enqueueScripts() {
if ( ! $this->isAllowed() || ! aioseo()->helpers->isScreenBase( 'post' ) ) {
return;
}
// Only enqueue this script if the post-settings-metabox is already enqueued.
if ( wp_script_is( 'aioseo/js/src/vue/standalone/post-settings/main.js', 'enqueued' ) ) {
aioseo()->core->assets->load( 'src/vue/standalone/limit-modified-date/main.js' );
}
}
/**
* Adds the Limit Modified Date field to the post object to prevent it from being dropped.
*
* @since 4.1.8
*
* @param object $preparedPost The post data.
* @param \WP_REST_Request $restRequest The request.
* @return object The modified post data.
*/
public function addLimitModifiedDateValue( $preparedPost, $restRequest = null ) {
if ( 'PUT' !== $restRequest->get_method() ) {
return $preparedPost;
}
$params = $restRequest->get_json_params();
if ( empty( $params ) || ! isset( $params['aioseo_limit_modified_date'] ) ) {
return $preparedPost;
}
$preparedPost->aioseo_limit_modified_date = $params['aioseo_limit_modified_date'];
return $preparedPost;
}
/**
* Resets the modified date when a post is updated if the Limit Modified Date option is enabled.
*
* @since 4.1.8
*
* @param array $data An array of slashed, sanitized, and processed post data.
* @param array $postArray An array of sanitized (and slashed) but otherwise unmodified post data.
* @return array The modified sanitized post data.
*/
public function resetModifiedDate( $data, $postArray = [] ) {
// If the ID isn't set, a new post is being inserted.
if ( ! isset( $postArray['ID'] ) ) {
return $data;
}
static $shouldReset = false;
// Handle the REST API request from the Block Editor.
if ( aioseo()->helpers->isRestApiRequest() ) {
// If the value isn't set, then the value wasn't changed in the editor, and we can grab it from the post.
if ( ! isset( $postArray['aioseo_limit_modified_date'] ) ) {
$aioseoPost = Models\Post::getPost( $postArray['ID'] );
if ( $aioseoPost->exists() && $aioseoPost->limit_modified_date ) {
$shouldReset = true;
}
} else {
if ( $postArray['aioseo_limit_modified_date'] ) {
$shouldReset = true;
}
}
}
// Handle the POST request.
if ( isset( $postArray['aioseo-post-settings'] ) ) {
$aioseoData = json_decode( stripslashes( $postArray['aioseo-post-settings'] ) );
if ( ! empty( $aioseoData->limit_modified_date ) ) {
$shouldReset = true;
}
}
// Handle post revision.
if ( ! empty( $GLOBALS['action'] ) && in_array( $GLOBALS['action'], [ 'restore', 'inline-save' ], true ) ) {
$aioseoPost = Models\Post::getPost( $postArray['ID'] );
if ( $aioseoPost->exists() && $aioseoPost->limit_modified_date ) {
$shouldReset = true;
}
}
foreach ( aioseo()->standalone->pageBuilderIntegrations as $pageBuilder ) {
if ( $pageBuilder->isBuiltWith( $postArray['ID'] ) && $pageBuilder->limitModifiedDate( $postArray['ID'] ) ) {
$shouldReset = true;
break;
}
}
if ( $shouldReset && isset( $postArray['post_modified'], $postArray['post_modified_gmt'] ) ) {
$originalPost = get_post( $postArray['ID'] );
$data['post_modified'] = $originalPost->post_modified;
$data['post_modified_gmt'] = $originalPost->post_modified_gmt;
}
return $data;
}
/**
* Limits the modified date for WooCommerce products.
*
* @since 4.8.1
*
* @param \WC_Product $product The WooCommerce product.
* @return void
*/
public function limitWooCommerceModifiedDate( $product ) {
if ( ! isset( $_POST['PostSettingsNonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['PostSettingsNonce'] ) ), 'aioseoPostSettingsNonce' ) ) {
return;
}
if ( ! isset( $_POST['aioseo-post-settings'] ) ) {
return;
}
$aioseoData = json_decode( sanitize_text_field( wp_unslash( ( $_POST['aioseo-post-settings'] ) ) ) );
if ( empty( $aioseoData ) || empty( $aioseoData->limit_modified_date ) ) {
return;
}
$product->set_date_modified( get_post_field( 'post_modified', $product->get_id() ) );
}
/**
* Add the checkbox in the Classic Editor.
*
* @since 4.1.8
*
* @param \WP_Post $post The post object.
* @return void
*/
public function classicEditorField( $post ) {
if ( ! $this->isAllowed( $post->post_type ) ) {
return;
}
?>
<div class="misc-pub-section">
<div id="aioseo-limit-modified-date"></div>
</div>
<?php
}
/**
* Check if the Limit Modified Date functionality is allowed to run.
*
* @since 4.1.8
*
* @param string $postType The current post type.
* @return bool Whether the functionality is allowed.
*/
private function isAllowed( $postType = '' ) {
if ( empty( $postType ) ) {
$postType = get_post_type();
}
if ( class_exists( 'Limit_Modified_Date', false ) ) {
return false;
}
if ( ! $this->isAllowedPostType( $postType ) ) {
return false;
}
if ( ! aioseo()->access->hasCapability( 'aioseo_page_general_settings' ) ) {
return false;
}
return true;
}
/**
* Check if the given post type is allowed to limit the modified date.
*
* @since 4.1.8
*
* @param string $postType The post type name.
* @return bool Whether the post type is allowed.
*/
private function isAllowedPostType( $postType ) {
$dynamicOptions = aioseo()->dynamicOptions->noConflict();
$postTypes = aioseo()->helpers->getPublicPostTypes( true );
$postTypes = apply_filters( 'aioseo_limit_modified_date_post_types', $postTypes );
if ( ! in_array( $postType, $postTypes, true ) ) {
return false;
}
if ( ! $dynamicOptions->searchAppearance->postTypes->has( $postType ) || ! $dynamicOptions->searchAppearance->postTypes->$postType->advanced->showMetaBox ) {
return false;
}
return true;
}
} SetupWizard.php 0000666 00000015073 15114751622 0007554 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class that holds our setup wizard.
*
* @since 4.0.0
*/
class SetupWizard {
/**
* Class constructor.
*
* @since 4.0.0
*/
public function __construct() {
if ( ! is_admin() || wp_doing_cron() || wp_doing_ajax() ) {
return;
}
add_action( 'admin_menu', [ $this, 'addDashboardPage' ] );
add_action( 'admin_head', [ $this, 'hideDashboardPageFromMenu' ] );
add_action( 'admin_init', [ $this, 'maybeLoadOnboardingWizard' ] );
add_action( 'admin_init', [ $this, 'redirect' ], 9999 );
}
/**
* Onboarding Wizard redirect.
*
* This function checks if a new install or update has just occurred. If so,
* then we redirect the user to the appropriate page.
*
* @since 4.0.0
*
* @return void
*/
public function redirect() {
// Check if we should consider redirection.
if ( ! aioseo()->core->cache->get( 'activation_redirect' ) ) {
return;
}
// If we are redirecting, clear the transient so it only happens once.
aioseo()->core->cache->delete( 'activation_redirect' );
// Check option to disable welcome redirect.
if ( get_option( 'aioseo_activation_redirect', false ) ) {
return;
}
// Only do this for single site installs.
if ( isset( $_GET['activate-multi'] ) || is_network_admin() ) { // phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
return;
}
wp_safe_redirect( admin_url( 'index.php?page=aioseo-setup-wizard' ) );
exit;
}
/**
* Adds a dashboard page for our setup wizard.
*
* @since 4.0.0
*
* @return void
*/
public function addDashboardPage() {
add_dashboard_page( '', '', aioseo()->admin->getPageRequiredCapability( 'aioseo-setup-wizard' ), 'aioseo-setup-wizard', '' );
}
/**
* Hide the dashboard page from the menu.
*
* @since 4.1.5
*
* @return void
*/
public function hideDashboardPageFromMenu() {
remove_submenu_page( 'index.php', 'aioseo-setup-wizard' );
}
/**
* Checks to see if we should load the setup wizard.
*
* @since 4.0.0
*
* @return void
*/
public function maybeLoadOnboardingWizard() {
// Don't load the interface if doing an ajax call.
if ( wp_doing_ajax() || wp_doing_cron() ) {
return;
}
// Check for wizard-specific parameter
// Allow plugins to disable the setup wizard
// Check if current user is allowed to save settings.
if (
// phpcs:disable HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
! isset( $_GET['page'] ) ||
'aioseo-setup-wizard' !== sanitize_text_field( wp_unslash( $_GET['page'] ) ) ||
// phpcs:enable
! current_user_can( aioseo()->admin->getPageRequiredCapability( 'aioseo-setup-wizard' ) )
) {
return;
}
set_current_screen();
// Remove an action in the Gutenberg plugin ( not core Gutenberg ) which throws an error.
remove_action( 'admin_print_styles', 'gutenberg_block_editor_admin_print_styles' );
// If we are redirecting, clear the transient so it only happens once.
aioseo()->core->cache->delete( 'activation_redirect' );
$this->loadOnboardingWizard();
}
/**
* Load the Onboarding Wizard template.
*
* @since 4.0.0
*
* @return void
*/
private function loadOnboardingWizard() {
$this->enqueueScripts();
$this->setupWizardHeader();
$this->setupWizardContent();
$this->setupWizardFooter();
exit;
}
/**
* Enqueue's scripts for the setup wizard.
*
* @since 4.0.0
*
* @return void
*/
public function enqueueScripts() {
// We don't want any plugin adding notices to our screens. Let's clear them out here.
remove_all_actions( 'admin_notices' );
remove_all_actions( 'network_admin_notices' );
remove_all_actions( 'all_admin_notices' );
aioseo()->core->assets->load( 'src/vue/standalone/setup-wizard/main.js', [], aioseo()->helpers->getVueData( 'setup-wizard' ) );
aioseo()->main->enqueueTranslations();
wp_enqueue_style( 'common' );
wp_enqueue_media();
}
/**
* Outputs the simplified header used for the Onboarding Wizard.
*
* @since 4.0.0
*
* @return void
*/
public function setupWizardHeader() {
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta name="viewport" content="width=device-width"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>
<?php
// Translators: 1 - The plugin name ("All in One SEO").
echo sprintf( esc_html__( '%1$s › Onboarding Wizard', 'all-in-one-seo-pack' ), esc_html( AIOSEO_PLUGIN_SHORT_NAME ) );
?>
</title>
</head>
<body class="aioseo-setup-wizard">
<?php
}
/**
* Outputs the content of the current step.
*
* @since 4.0.0
*
* @return void
*/
public function setupWizardContent() {
echo '<div id="aioseo-app">';
aioseo()->templates->getTemplate( 'admin/settings-page.php' );
echo '</div>';
}
/**
* Outputs the simplified footer used for the Onboarding Wizard.
*
* @since 4.0.0
*
* @return void
*/
public function setupWizardFooter() {
?>
<?php
wp_print_scripts( 'aioseo-vendors' );
wp_print_scripts( 'aioseo-common' );
wp_print_scripts( 'aioseo-setup-wizard-script' );
do_action( 'admin_footer', '' );
do_action( 'admin_print_footer_scripts' );
// do_action( 'customize_controls_print_footer_scripts' );
?>
</body>
</html>
<?php
}
/**
* Check whether or not the Setup Wizard is completed.
*
* @since 4.2.0
*
* @return boolean Whether or not the Setup Wizard is completed.
*/
public function isCompleted() {
$wizard = (string) aioseo()->internalOptions->internal->wizard;
$wizard = json_decode( $wizard );
if ( ! $wizard ) {
return false;
}
$totalStageCount = count( $wizard->stages );
$currentStageCount = array_search( $wizard->currentStage, $wizard->stages, true );
// If not found, let's assume it's completed.
if ( false === $currentStageCount ) {
return true;
}
return $currentStageCount + 1 === $totalStageCount;
}
/**
* Get the next stage of the wizard.
*
* @since 4.6.2
*
* @return string The next stage or empty.
*/
public function getNextStage() {
$wizard = (string) aioseo()->internalOptions->internal->wizard;
$wizard = json_decode( $wizard );
if ( ! $wizard ) {
return '';
}
// Default to success.
$nextStage = 'success';
// Get the next stage of the wizard.
$currentStageIndex = array_search( $wizard->currentStage, $wizard->stages, true );
if ( ! empty( $wizard->stages[ $currentStageIndex + 1 ] ) ) {
$nextStage = $wizard->stages[ $currentStageIndex + 1 ];
}
return $nextStage;
}
} UserProfileTab.php 0000666 00000012537 15114751622 0010163 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Pro\Standalone as ProStandalone;
/**
* Registers the standalone components.
*
* @since 4.2.2
*/
class UserProfileTab {
/**
* Class constructor.
*
* @since 4.2.2
*/
public function __construct() {
if ( ! is_admin() ) {
return;
}
add_action( 'admin_enqueue_scripts', [ $this, 'enqueueScript' ] );
add_action( 'profile_update', [ $this, 'updateUserSocialProfiles' ] );
}
/**
* Enqueues the script.
*
* @since 4.2.2
*
* @return void
*/
public function enqueueScript() {
if ( apply_filters( 'aioseo_user_profile_tab_disable', false ) ) {
return;
}
$screen = aioseo()->helpers->getCurrentScreen();
if ( empty( $screen->id ) ) {
return;
}
if ( ! in_array( $screen->id, [ 'user-edit', 'profile' ], true ) ) {
if ( 'follow-up_page_followup-emails-reports' === $screen->id ) {
aioseo()->core->assets->load( 'src/vue/standalone/user-profile-tab/follow-up-emails-nav-bar.js' );
}
return;
}
global $user_id; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
if ( ! intval( $user_id ) ) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName
return;
}
aioseo()->core->assets->load( 'src/vue/standalone/user-profile-tab/main.js', [], $this->getVueData() );
// Load script again so we can add extra data to localize the strings.
aioseo()->core->assets->load( 'src/vue/standalone/user-profile-tab/main.js', [], [
'translations' => aioseo()->helpers->getJedLocaleData( 'aioseo-eeat' )
], 'eeat' );
}
/**
* Returns the data Vue requires.
*
* @since 4.2.2
*
* @return array
*/
public function getVueData() {
global $user_id; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$socialProfiles = $this->getSocialProfiles();
foreach ( $socialProfiles as $platformKey => $v ) {
$metaName = 'aioseo_' . aioseo()->helpers->toSnakeCase( $platformKey );
$socialProfiles[ $platformKey ] = get_user_meta( $user_id, $metaName, true ); // phpcs:ignore Squiz.NamingConventions.ValidVariableName
}
$sameUsername = get_user_meta( $user_id, 'aioseo_profiles_same_username', true ); // phpcs:ignore Squiz.NamingConventions.ValidVariableName
if ( empty( $sameUsername ) ) {
$sameUsername = [
'enable' => false,
'username' => '',
'included' => [ 'facebookPageUrl', 'twitterUrl', 'tiktokUrl', 'pinterestUrl', 'instagramUrl', 'youtubeUrl', 'linkedinUrl' ] // Same as in Options.php.
];
}
$additionalurls = get_user_meta( $user_id, 'aioseo_profiles_additional_urls', true ); // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$extraVueData = [
'userProfile' => [
'userData' => get_userdata( $user_id )->data, // phpcs:ignore Squiz.NamingConventions.ValidVariableName
'profiles' => [
'sameUsername' => $sameUsername,
'urls' => $socialProfiles,
'additionalUrls' => $additionalurls
],
'isWooCommerceFollowupEmailsActive' => aioseo()->helpers->isWooCommerceFollowupEmailsActive()
]
];
$vueData = aioseo()->helpers->getVueData();
$vueData = array_merge( $vueData, $extraVueData );
return $vueData;
}
/**
* Updates the user social profile URLs when a user's profile is updated.
*
* @since 4.2.2
*
* @param int $userId The user ID.
* @return void
*/
public function updateUserSocialProfiles( $userId ) {
if ( empty( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), 'update-user_' . $userId ) ) {
return;
}
if ( empty( $_POST['aioseo-user-social-profiles'] ) ) {
return;
}
$data = json_decode( sanitize_text_field( wp_unslash( $_POST['aioseo-user-social-profiles'] ) ), true );
if ( empty( $data ) ) {
return;
}
$sanitizedIncluded = [];
foreach ( $data['sameUsername']['included'] as $platformKey ) {
$sanitizedIncluded[] = sanitize_text_field( $platformKey );
}
$sanitizedSameUsernameData = [
'enable' => (bool) $data['sameUsername']['enable'],
'username' => sanitize_text_field( $data['sameUsername']['username'] ),
'included' => array_filter( $sanitizedIncluded )
];
update_user_meta( $userId, 'aioseo_profiles_same_username', $sanitizedSameUsernameData );
foreach ( $data['urls'] as $platformKey => $value ) {
$value = sanitize_text_field( $value );
$metaName = 'aioseo_' . aioseo()->helpers->toSnakeCase( $platformKey );
update_user_meta( $userId, $metaName, $value );
}
$additionalUrls = sanitize_text_field( $data['additionalUrls'] );
$sanitizedAdditionalUrls = preg_replace( '/\h/', "\n", (string) $additionalUrls );
update_user_meta( $userId, 'aioseo_profiles_additional_urls', $sanitizedAdditionalUrls );
}
/**
* Returns a list of supported social profiles.
*
* @since 4.2.2
*
* @return array
*/
public function getSocialProfiles() {
return [
'facebookPageUrl' => '',
'twitterUrl' => '',
'instagramUrl' => '',
'tiktokUrl' => '',
'pinterestUrl' => '',
'youtubeUrl' => '',
'linkedinUrl' => '',
'tumblrUrl' => '',
'yelpPageUrl' => '',
'soundCloudUrl' => '',
'wikipediaUrl' => '',
'myspaceUrl' => '',
'wordPressUrl' => '',
'blueskyUrl' => '',
'threadsUrl' => ''
];
}
} BbPress/Component.php 0000666 00000005100 15114751622 0010563 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\BbPress;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* bbPress Component class.
*
* @since 4.8.1
*/
class Component {
/**
* The current component template type.
*
* @since 4.8.1
*
* @var string|null
*/
public $templateType = null;
/**
* The topic single page data.
*
* @since 4.8.1
*
* @var array
*/
public $topic = [];
/**
* Class constructor.
*
* @since 4.8.1
*/
public function __construct() {
if ( is_admin() ) {
return;
}
$this->setTemplateType();
$this->setTopic();
}
/**
* Sets the template type.
*
* @since 4.8.1
*
* @return void
*/
private function setTemplateType() {
if ( function_exists( 'bbp_is_single_topic' ) && bbp_is_single_topic() ) {
$this->templateType = 'bbp-topic_single';
}
}
/**
* Sets the topic data.
*
* @since 4.8.1
*
* @return void
*/
private function setTopic() {
if ( 'bbp-topic_single' !== $this->templateType ) {
return;
}
if (
! function_exists( 'bbpress' ) ||
! function_exists( 'bbp_has_replies' ) ||
! bbp_has_replies()
) {
return;
}
$replyQuery = bbpress()->reply_query ?? null;
$replies = $replyQuery->posts ?? [];
$mainTopic = is_array( $replies ) && ! empty( $replies ) ? array_shift( $replies ) : null;
if ( $mainTopic instanceof \WP_Post ) {
$this->topic = [
'title' => $mainTopic->post_title,
'content' => $mainTopic->post_content,
'date' => $mainTopic->post_date,
'author' => get_the_author_meta( 'display_name', $mainTopic->post_author ),
];
$comments = [];
if ( ! empty( $replies ) ) {
foreach ( $replies as $reply ) {
if ( ! $reply instanceof \WP_Post ) {
continue;
}
$comments[ $reply->ID ] = [
'content' => $reply->post_content,
'date_recorded' => $reply->post_date,
'user_fullname' => get_the_author_meta( 'display_name', $reply->post_author ),
];
if ( ! empty( $reply->reply_to ) ) {
$comments[ $reply->reply_to ]['children'][] = $comments[ $reply->ID ];
unset( $comments[ $reply->ID ] );
}
}
$this->topic['comment'] = array_values( $comments );
}
return;
}
$this->resetComponent();
}
/**
* Resets some of the component properties.
*
* @since 4.8.1
*
* @return void
*/
private function resetComponent() {
$this->templateType = null;
}
/**
* Determines the schema type for the current component.
*
* @since 4.8.1
*
* @return void
*/
public function determineSchemaGraphsAndContext() {
}
} BbPress/BbPress.php 0000666 00000002273 15114751622 0010171 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\BbPress;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles the bbPress integration with AIOSEO.
*
* @since 4.8.1
*/
class BbPress {
/**
* Instance of the Component class.
*
* @since 4.8.1
*
* @var Component
*/
public $component;
/**
* Class constructor.
*
* @since 4.8.1
*/
public function __construct() {
if (
aioseo()->helpers->isAjaxCronRestRequest() ||
! aioseo()->helpers->isPluginActive( 'bbpress' )
) {
return;
}
// Hook into `plugins_loaded` to ensure bbPress has loaded some necessary functions.
add_action( 'plugins_loaded', [ $this, 'maybeLoad' ], 20 );
}
/**
* Hooked into `plugins_loaded` action hook.
*
* @since 4.8.1
*
* @return void
*/
public function maybeLoad() {
// If the bbPress version is below 2 we bail.
if ( ! function_exists( 'bbp_get_version' ) || version_compare( bbp_get_version(), '2', '<' ) ) {
return;
}
add_action( 'wp', [ $this, 'setComponent' ] );
}
/**
* Hooked into `wp` action hook.
*
* @since 4.8.1
*
* @return void
*/
public function setComponent() {
$this->component = new Component();
}
} FlyoutMenu.php 0000666 00000003405 15114751622 0007376 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles the flyout menu.
*
* @since 4.2.0
*/
class FlyoutMenu {
/**
* Class constructor.
*
* @since 4.2.0
*/
public function __construct() {
if (
! is_admin() ||
wp_doing_ajax() ||
wp_doing_cron() ||
! $this->isEnabled()
) {
return;
}
add_action( 'admin_enqueue_scripts', [ $this, 'enqueueAssets' ], 11 );
add_filter( 'admin_body_class', [ $this, 'addBodyClass' ] );
}
/**
* Enqueues the required assets.
*
* @since 4.2.0
*
* @return void
*/
public function enqueueAssets() {
if ( ! $this->shouldEnqueue() ) {
return;
}
aioseo()->core->assets->load( 'src/vue/standalone/flyout-menu/main.js' );
}
/**
* Filters the CSS classes for the body tag in the admin.
*
* @since 4.2.0
*
* @param string $classes Space-separated list of CSS classes.
* @return string Space-separated list of CSS classes.
*/
public function addBodyClass( $classes ) {
if ( $this->shouldEnqueue() ) {
// This adds a bottom margin to our menu so that we push the footer down and prevent the flyout menu from overlapping the "Save Changes" button.
$classes .= ' aioseo-flyout-menu-enabled ';
}
return $classes;
}
/**
* Checks whether the flyout menu script should be enqueued.
*
* @since 4.2.0
*
* @return bool Whether the flyout menu script should be enqueued.
*/
private function shouldEnqueue() {
return aioseo()->admin->isAioseoScreen();
}
/**
* Checks whether the flyout menu is enabled.
*
* @since 4.2.0
*
* @return bool Whether the flyout menu is enabled.
*/
public function isEnabled() {
return apply_filters( 'aioseo_flyout_menu_enable', true );
}
} Blocks/FaqPage.php 0000666 00000001075 15114751622 0010011 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\Blocks;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* FaqPage Block.
*
* @since 4.2.3
*/
class FaqPage extends Blocks {
/**
* Register the block.
*
* @since 4.2.3
*
* @return void
*/
public function register() {
aioseo()->blocks->registerBlock( 'aioseo/faq',
[
'render_callback' => function( $attributes, $content ) {
if ( isset( $attributes['hidden'] ) && true === $attributes['hidden'] ) {
return '';
}
return $content;
},
]
);
}
} Blocks/Blocks.php 0000666 00000001166 15114751622 0007723 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\Blocks;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Loads core classes.
*
* @since 4.2.3
*/
abstract class Blocks {
/**
* Class constructor.
*
* @since 4.2.3
*/
public function __construct() {
add_action( 'init', [ $this, 'init' ] );
}
/**
* Initializes our blocks.
*
* @since 4.2.3
*
* @return void
*/
public function init() {
$this->register();
}
/**
* Registers the block. This is a wrapper to be extended in the child class.
*
* @since 4.2.3
*
* @return void
*/
public function register() {}
} Blocks/TableOfContents.php 0000666 00000000616 15114751622 0011537 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\Blocks;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Table of Contents Block.
*
* @since 4.2.3
*/
class TableOfContents extends Blocks {
/**
* Register the block.
*
* @since 4.2.3
*
* @return void
*/
public function register() {
aioseo()->blocks->registerBlock( 'aioseo/table-of-contents' );
}
} PublishPanel.php 0000666 00000001365 15114751622 0007660 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* Handles the Publish Panel in the Block Editor.
*
* @since 4.2.0
*/
class PublishPanel {
/**
* Class constructor.
*
* @since 4.2.0
*/
public function __construct() {
if ( ! is_admin() || wp_doing_ajax() || wp_doing_cron() ) {
return;
}
add_action( 'admin_enqueue_scripts', [ $this, 'enqueueScript' ] );
}
/**
* Enqueues the script.
*
* @since 4.2.0
*
* @return void
*/
public function enqueueScript() {
if ( ! aioseo()->helpers->isScreenBase( 'post' ) ) {
return;
}
aioseo()->core->assets->load( 'src/vue/standalone/publish-panel/main.js' );
}
} PageBuilders/Avada.php 0000666 00000005617 15114751622 0010660 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\PageBuilders;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Integrate our SEO Panel with Avada Page Builder.
*
* @since 4.5.2
*/
class Avada extends Base {
/**
* The plugin files.
*
* @since 4.5.2
*
* @var array
*/
public $plugins = [
'fusion-builder/fusion-builder.php'
];
/**
* The integration slug.
*
* @since 4.5.2
*
* @var string
*/
public $integrationSlug = 'avada';
/**
* Init the integration.
*
* @since 4.5.2
*
* @return void
*/
public function init() {
add_action( 'fusion_enqueue_live_scripts', [ $this, 'enqueue' ] );
add_action( 'fusion_builder_admin_scripts_hook', [ $this, 'enqueue' ] );
add_action( 'wp_footer', [ $this, 'addSidebarWrapper' ] );
}
/**
* Check if we are in the front-end builder.
*
* @since 4.5.2
*
* @return boolean Whether or not we are in the front-end builder.
*/
public function isBuilder() {
return function_exists( 'fusion_is_builder_frame' ) && fusion_is_builder_frame();
}
/**
* Check if we are in the front-end preview.
*
* @since 4.5.2
*
* @return boolean Whether or not we are in the front-end preview.
*/
public function isPreview() {
return function_exists( 'fusion_is_preview_frame' ) && fusion_is_preview_frame();
}
/**
* Adds the sidebar wrapper in footer when is in page builder.
*
* @since 4.5.2
*
* @return void
*/
public function addSidebarWrapper() {
if ( ! $this->isBuilder() ) {
return;
}
echo '<div id="fusion-builder-aioseo-sidebar"></div>';
}
/**
* Enqueue the scripts and styles.
*
* @since 4.5.2
*
* @return void
*/
public function enqueue() {
if ( ! aioseo()->postSettings->canAddPostSettingsMetabox( get_post_type( $this->getPostId() ) ) ) {
return;
}
parent::enqueue();
}
/**
* Returns whether or not the given Post ID was built with WPBakery.
*
* @since 4.5.2
*
* @param int $postId The Post ID.
* @return boolean Whether or not the Post was built with WPBakery.
*/
public function isBuiltWith( $postId ) {
return 'active' === get_post_meta( $postId, 'fusion_builder_status', true );
}
/**
* Returns whether should or not limit the modified date.
*
* @since 4.5.2
*
* @param int $postId The Post ID.
* @return boolean Whether or not sholud limit the modified date.
*/
public function limitModifiedDate( $postId ) {
// This method is supposed to be used in the `wp_ajax_fusion_app_save_post_content` action.
if ( ! isset( $_POST['fusion_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['fusion_load_nonce'] ) ), 'fusion_load_nonce' ) ) {
return false;
}
$editorPostId = ! empty( $_REQUEST['post_id'] ) ? intval( $_REQUEST['post_id'] ) : 0;
if ( $editorPostId !== $postId ) {
return false;
}
return ! empty( $_REQUEST['query']['aioseo_limit_modified_date'] );
}
} PageBuilders/SeedProd.php 0000666 00000007154 15114751622 0011347 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\PageBuilders;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Integrate our SEO Panel with SeedProd Page Builder.
*
* @since 4.1.7
*/
class SeedProd extends Base {
/**
* The plugin files.
*
* @since 4.1.7
*
* @var array
*/
public $plugins = [
'coming-soon/coming-soon.php',
'seedprod-coming-soon-pro-5/seedprod-coming-soon-pro-5.php',
];
/**
* The integration slug.
*
* @since 4.1.7
*
* @var string
*/
public $integrationSlug = 'seedprod';
/**
* Init the integration.
*
* @since 4.1.7
*
* @return void
*/
public function init() {
$postType = get_post_type( $this->getPostId() );
if ( ! aioseo()->postSettings->canAddPostSettingsMetabox( $postType ) ) {
return;
}
// SeedProd de-enqueues and de-register scripts/styles on priority PHP_INT_MAX.
// Thus, we need to enqueue our scripts at the same priority for more compatibility.
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ], PHP_INT_MAX );
add_filter( 'style_loader_tag', [ $this, 'replaceStyleTag' ], 10, 2 );
}
/**
* Enqueue the scripts and styles.
*
* @since 4.1.7
*
* @return void
*/
public function enqueue() {
if ( ! $this->isBuilderScreen() ) {
return;
}
parent::enqueue();
}
/**
* Check whether or not is builder screen.
*
* @since 4.1.7
*
* @return boolean Whether or not is builder screen.
*/
public function isBuilderScreen() {
$currentScreen = aioseo()->helpers->getCurrentScreen();
return $currentScreen && preg_match( '/seedprod.*?_builder$/i', (string) $currentScreen->base );
}
/**
* Replace original tag to prevent being removed by SeedProd.
*
* @param string $tag The <link> tag for the enqueued style.
* @param string $handle The style's registered handle.
* @return string The tag.
*/
public function replaceStyleTag( $tag, $handle = '' ) {
if ( ! $this->isBuilderScreen() ) {
return $tag;
}
$aioseoCommonHandle = 'aioseo-' . $this->integrationSlug . '-common';
if ( $aioseoCommonHandle === $handle ) {
// All the *common.css links are removed from SeedProd.
// https://github.com/awesomemotive/seedprod-plugins/blob/32854442979bfa068aadf9b8a8a929e5f9f353e5/seedprod-pro/resources/views/builder.php#L406
$tag = str_ireplace( 'href=', 'data-href=', $tag );
}
return $tag;
}
/**
* Returns whether or not the given Post ID was built with SeedProd.
*
* @since 4.1.7
*
* @param int $postId The Post ID.
* @return boolean Whether or not the Post was built with SeedProd.
*/
public function isBuiltWith( $postId ) {
$isSeedProd = get_post_meta( $postId, '_seedprod_page', true );
if ( ! empty( $isSeedProd ) ) {
return true;
}
return false;
}
/**
* Checks whether or not we should prevent the date from being modified.
*
* @since 4.5.2
*
* @param int $postId The Post ID.
* @return bool Whether or not we should prevent the date from being modified.
*/
public function limitModifiedDate( $postId ) {
// This method is supposed to be used in the `wp_ajax_seedprod_pro_save_lpage` action.
if ( wp_doing_ajax() && ! check_ajax_referer( 'seedprod_nonce', false, false ) ) {
return false;
}
$landingPageId = ! empty( $_REQUEST['lpage_id'] ) ? (int) $_REQUEST['lpage_id'] : false;
if ( $landingPageId !== $postId ) {
return false;
}
$settings = ! empty( $_REQUEST['settings'] ) ? json_decode( sanitize_text_field( wp_unslash( $_REQUEST['settings'] ) ) ) : false;
if ( empty( $settings ) || empty( $settings->aioseo_limit_modified_date ) ) {
return false;
}
return true;
}
} PageBuilders/ThriveArchitect.php 0000666 00000031364 15114751622 0012732 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\PageBuilders;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Integrate our SEO Panel with Thrive Architect Page Builder.
*
* @since 4.6.6
*/
class ThriveArchitect extends Base {
/**
* The plugin files.
*
* @since 4.6.6
*
* @var array
*/
public $plugins = [
'thrive-visual-editor/thrive-visual-editor.php'
];
/**
* The integration slug.
*
* @since 4.6.6
*
* @var string
*/
public $integrationSlug = 'thrive-architect';
/**
* Init the integration.
*
* @since 4.6.6
*
* @return void
*/
public function init() {
add_filter( 'tcb_allowed_ajax_options', [ $this, 'makeSettingsAllowed' ] );
if ( ! aioseo()->postSettings->canAddPostSettingsMetabox( get_post_type( $this->getPostId() ) ) ) {
return;
}
add_action( 'tcb_main_frame_enqueue', [ $this, 'enqueue' ] );
add_filter( 'tve_main_js_dependencies', [ $this, 'mainJsDependencies' ] );
add_action( 'tcb_right_sidebar_content_settings', [ $this, 'addSettingsTab' ] );
add_action( 'tcb_sidebar_extra_links', [ $this, 'addSidebarButton' ] );
add_filter( 'tcb_main_frame_localize', [ $this, 'localizeData' ] );
}
/**
* Overrides the parent enqueue to add WordPress styles that we need.
*
* @since 4.6.6
*
* @return void
*/
public function enqueue() {
wp_enqueue_style( 'common' );
wp_enqueue_style( 'buttons' );
wp_enqueue_style( 'forms' );
wp_enqueue_style( 'list-tables' );
wp_enqueue_style( 'wp-components' );
print_admin_styles();
parent::enqueue();
}
/**
* Add our javascript to the plugin dependencies.
*
* @since 4.6.6
*
* @param array $dependencies The dependencies.
* @return array The dependencies.
*/
public function mainJsDependencies( $dependencies ) {
$dependencies[] = aioseo()->core->assets->jsHandle( "src/vue/standalone/page-builders/{$this->integrationSlug}/main.js" );
return $dependencies;
}
/**
* Add the extra link to the sidebar.
*
* @since 4.6.6
*
* @return void
*/
public function addSidebarButton() {
$tooltip = sprintf(
// Translators: 1 - The plugin short name ("AIOSEO").
esc_html__( '%1$s Settings', 'all-in-one-seo-pack' ),
AIOSEO_PLUGIN_SHORT_NAME
);
// phpcs:disable Generic.Files.LineLength.MaxExceeded
?>
<a href="javascript:void(0)" class="mouseenter mouseleave sidebar-item tcb-sidebar-icon-aioseo" data-position="left" data-toggle="settings" data-tooltip="<?php echo esc_attr( $tooltip ); ?>">
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.0011 19C14.9722 19 19.0021 14.9706 19.0021 10C19.0021 5.02944 14.9722 1 10.0011 1C5.02991 1 1 5.02944 1 10C1 14.9706 5.02991 19 10.0011 19Z" stroke="currentColor"/>
<path d="M9.99664 13.3228C9.99896 13.2104 9.47813 13.1752 9.37307 13.141C8.56228 12.8777 8.04027 12.3293 7.78204 11.5205C7.6493 11.1043 7.68851 10.6765 7.68163 10.2515C7.68162 10.2511 7.68134 10.2507 7.68093 10.2506V10.2506C7.68051 10.2504 7.68023 10.25 7.68023 10.2496C7.68069 9.99579 7.67884 9.74246 7.68115 9.48867C7.683 9.31099 7.74131 9.25453 7.92133 9.25222C8.07128 9.25037 8.22168 9.24482 8.37116 9.25407C8.48454 9.26101 8.86945 9.25407 8.86945 9.25407M9.99664 13.3228C9.98877 13.7037 10.0003 14.1192 10.0008 14.5M9.99664 13.3228C10.0036 13.7152 9.99664 14.1076 10.0008 14.5M9.99664 13.3228C9.99863 13.2265 10.5453 13.1946 10.6332 13.1715C11.6884 12.8929 12.42 11.955 12.4311 10.8639C12.4358 10.4137 12.433 9.96389 12.432 9.51366C12.432 9.30312 12.3788 9.25268 12.1641 9.25176C12.0197 9.25083 11.8749 9.24435 11.7314 9.25407C11.6213 9.26148 11.2793 9.25176 11.2793 9.25176M10.0008 14.5C10.0008 14.7878 9.72149 14.8117 9.50075 15C9.29018 15.1795 8.77054 15.5587 8.52758 15.6966C8.32442 15.8118 8.12033 15.8428 7.90097 15.7401C7.72373 15.6573 7.53862 15.5916 7.36276 15.5059C7.13877 15.3963 7.04344 15.1936 7.08879 14.947C7.1323 14.7091 7.17765 14.4718 7.22578 14.2348C7.27529 13.9933 7.21745 13.7897 7.02632 13.6291C6.78706 13.4283 6.5677 13.2071 6.37195 12.9637C6.21321 12.7671 6.01098 12.7102 5.76941 12.762C5.5445 12.8101 5.31866 12.8559 5.09282 12.9008C4.84339 12.9503 4.64902 12.8587 4.53425 12.6329C4.42457 12.4173 4.33433 12.1924 4.2589 11.9624C4.1793 11.719 4.24085 11.5191 4.4491 11.3683C4.64532 11.2262 4.84616 11.0911 5.04794 10.9574C5.26961 10.8107 5.34828 10.6071 5.31866 10.348C5.2858 10.0606 5.28673 9.7714 5.31635 9.48405C5.34411 9.21613 5.25711 9.01253 5.02757 8.86585C4.8383 8.74461 4.65318 8.6169 4.46853 8.4878C4.23576 8.32492 4.16541 8.12086 4.26028 7.85525C4.33803 7.6387 4.42318 7.42446 4.51852 7.21531C4.62218 6.98811 4.80822 6.89186 5.05349 6.93258C5.28025 6.97006 5.50609 7.0168 5.731 7.06585C5.99154 7.12322 6.20812 7.06631 6.3775 6.84929C6.56261 6.61238 6.77781 6.40322 7.00503 6.2061C7.18829 6.04693 7.27205 5.8549 7.21143 5.60549C7.16006 5.3931 7.12906 5.17608 7.08509 4.96184C7.01429 4.61803 7.1036 4.42924 7.4257 4.28024C7.6085 4.19603 7.79453 4.11783 7.98335 4.04842C8.22399 3.9605 8.42762 4.02574 8.57385 4.23536C8.71546 4.43849 8.84967 4.64718 8.98341 4.85587C9.12317 5.07382 9.32032 5.15896 9.57392 5.12703C9.86131 5.09094 10.1492 5.09325 10.437 5.12564C10.6763 5.15248 10.8669 5.0715 11.0002 4.86698C11.1261 4.67402 11.251 4.48014 11.3778 4.28765C11.5611 4.01001 11.7467 3.94384 12.054 4.05952C12.2479 4.13217 12.4395 4.21176 12.6264 4.3006C12.8731 4.41813 12.9684 4.6134 12.9198 4.87993C12.8763 5.11777 12.8291 5.35469 12.7828 5.59207C12.737 5.82621 12.7944 6.0261 12.9804 6.18297C13.2234 6.38842 13.4437 6.61561 13.6473 6.86086C13.8005 7.04502 13.993 7.11443 14.2337 7.05474C14.4567 6.99921 14.6839 6.95896 14.9098 6.91407C15.1648 6.86317 15.3661 6.95988 15.4822 7.19217C15.5882 7.40364 15.6761 7.6225 15.7506 7.84693C15.8335 8.09726 15.771 8.29901 15.5558 8.45495C15.3596 8.59654 15.1583 8.73166 14.9565 8.86585C14.7473 9.00466 14.6645 9.19855 14.6913 9.44425C14.7237 9.74363 14.7242 10.0435 14.6946 10.3429C14.6691 10.6038 14.7552 10.8033 14.9783 10.9467C15.1624 11.0652 15.3429 11.1897 15.523 11.3146C15.7816 11.4946 15.8506 11.6973 15.7451 11.9879C15.6766 12.1771 15.5993 12.3636 15.5174 12.5473C15.3818 12.8504 15.1907 12.9401 14.8621 12.8721C14.6423 12.8263 14.4211 12.7888 14.2017 12.7398C13.9939 12.6935 13.8213 12.7574 13.689 12.911C13.4627 13.1738 13.2234 13.4218 12.9638 13.6527C12.8088 13.7906 12.7467 13.9706 12.7958 14.1849C12.8485 14.4148 12.8874 14.6476 12.9337 14.879C12.9957 15.189 12.8999 15.3856 12.6088 15.5235C12.4478 15.5999 12.2789 15.66 12.1178 15.7364C11.911 15.8345 11.7175 15.8058 11.5236 15.7003C11.2265 15.5388 10.741 15.2332 10.5009 15C10.3403 14.8441 10.0031 14.7207 10.0008 14.5ZM11.2793 9.25176C11.2848 8.85382 11.2873 8.01509 11.2804 7.61719C11.2795 7.56905 11.2791 7.5401 11.279 7.52286C11.2788 7.50546 11.2793 7.50858 11.2794 7.52598C11.2798 7.63906 11.2816 8.09163 11.2833 8.28906C11.2796 8.687 11.2714 8.85382 11.2793 9.25176ZM11.2793 9.25176C11.2793 9.25176 10.9086 9.25685 10.7873 9.255C10.2968 9.24806 9.80624 9.24852 9.31569 9.255C9.19999 9.25638 8.86945 9.25407 8.86945 9.25407M8.86945 9.25407C8.87593 8.8677 8.87547 8.34389 8.87408 7.95752C8.87346 7.78806 8.87262 7.62829 8.87143 7.54953C8.8709 7.51441 8.86954 7.51752 8.86963 7.55263C8.86985 7.62907 8.8701 7.7811 8.86945 7.95752C8.86853 8.34435 8.86251 8.8677 8.86945 9.25407Z" stroke="currentColor"/>
</svg>
</a>
<?php
//phpcs:enable Generic.Files.LineLength.MaxExceeded
}
/**
* Adds the settings tab for AIOSEO in the Thrive Architect page builder.
*
* @since 4.6.6
*
* @return void
*/
public function addSettingsTab() {
//phpcs:disable Generic.Files.LineLength.MaxExceeded
?>
<div class="tve-component s-item tcb-aioseo">
<div class="dropdown-header">
<div class="group-description s-name">
<?php echo esc_html( AIOSEO_PLUGIN_SHORT_NAME ); ?>
</div>
</div>
<div class="dropdown-content">
<div class="tcb-aioseo-settings">
<button class="click tcb-settings-modal-open-button s-item inside-button">
<span class="s-name">
<?php
printf(
// Translators: 1 - The plugin short name ("AIOSEO").
esc_html__( '%1$s Settings', 'all-in-one-seo-pack' ),
esc_html( AIOSEO_PLUGIN_SHORT_NAME )
);
?>
</span>
</button>
<div class="mt-10 button-group">
<div id="aioseo-score-btn-settings"></div>
<button type="button" class="p-3 action-btn click" id="settings-action-btn">
<svg class="when-active" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.61433 9.94582C10.145 11.0636 10.2253 12.3535 9.45767 13.2683C9.24696 13.5194 8.89896 13.533 8.66555 13.3372L6.22379 11.2883L4.64347 13.1717C4.62842 13.1896 4.59542 13.1925 4.58036 13.2104L3.42703 13.7098C3.28287 13.7722 3.12128 13.6366 3.15772 13.4838L3.44925 12.2613C3.4643 12.2434 3.47935 12.2254 3.4944 12.2075L5.07472 10.3241L2.63295 8.27524C2.3816 8.06433 2.35256 7.73431 2.56327 7.4832C3.3158 6.58636 4.59718 6.40838 5.7901 6.73691L7.81453 4.7983L7.06045 4.16555C6.80909 3.95464 6.78006 3.62462 6.99077 3.37351L7.7132 2.51255C7.90885 2.27937 8.25395 2.23272 8.50531 2.44363L13.3888 6.54141C13.6222 6.73725 13.6542 7.10028 13.4585 7.33345L12.7361 8.19441C12.5254 8.44552 12.1774 8.45917 11.944 8.26332L11.172 7.61551L9.61433 9.94582Z" fill="#FFFFFF"/>
</svg>
<svg class="when-inactive" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.87874 6.50704C5.88995 6.50899 5.90115 6.51097 5.91236 6.513L7.23686 5.29914L6.55461 4.72665C6.3212 4.5308 6.27436 4.18554 6.48527 3.93418L7.6905 2.49785C7.88635 2.26445 8.24956 2.23267 8.48297 2.42852L13.3665 6.52629C13.6179 6.73721 13.6317 7.08535 13.4358 7.31876L12.2306 8.75509C12.0197 9.00645 11.6895 9.03534 11.4381 8.82442L10.7738 8.26701L9.80841 9.78218C9.81235 9.79286 9.81625 9.80354 9.82011 9.81424L9.23164 9.32046L10.6275 7.16519L11.7766 8.12937L12.7408 6.9803L8.14451 3.12358L7.18033 4.27264L8.3294 5.23682L6.4644 6.99846L5.87874 6.50704ZM4.72914 6.45619C3.84314 6.53709 3.0184 6.91015 2.43354 7.63253C2.31301 7.77616 2.31817 8.02525 2.47976 8.16084L5.35242 10.5713L3.54458 12.7258L3.51445 12.7617L3.176 13.4568C3.09138 13.6305 3.28888 13.7962 3.44531 13.6827L4.07103 13.2287L4.10116 13.1928L5.909 11.0383L8.78167 13.4488C8.94326 13.5844 9.18946 13.5462 9.30998 13.4025C9.90734 12.6906 10.1364 11.8178 10.0663 10.9346L9.15211 10.1675C9.42355 10.9846 9.399 11.8779 8.95854 12.6181L3.26707 7.84242C3.90443 7.26739 4.79027 7.09684 5.64573 7.2253L4.72914 6.45619Z" fill="#50565F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.4242 11.9993L3.23163 4.28583L3.68158 3.7496L12.8741 11.463L12.4242 11.9993Z" fill="#50565F"/>
</svg>
</button>
</div>
</div>
</div>
</div>
<?php
//phpcs:enable Generic.Files.LineLength.MaxExceeded
}
/**
* Localizes the data by adding the 'is_aioseo_settings_enabled' option to the provided data array.
*
* @since 4.6.6
*
* @param array $data The data array to be localized.
* @return array The localized data array with the 'is_aioseo_settings_enabled' option added.
*/
public function localizeData( $data ) {
// We use get_option here since it is how Thrive Architect saves the settings.
$data['is_aioseo_settings_enabled'] = get_option( 'is_aioseo_settings_enabled', true );
return $data;
}
/**
* Adds 'is_aioseo_settings_enabled' to the list of allowed settings.
*
* @since 4.6.6
*
* @param array $options The array of allowed settings.
* @return array The updated array of allowed settings.
*/
public function makeSettingsAllowed( $options ) {
$options[] = 'is_aioseo_settings_enabled';
return $options;
}
/**
* Returns whether or not the given Post ID was built with Thrive Architect.
*
* @since 4.6.6
*
* @param int $postId The Post ID.
* @return boolean Whether or not the Post was built with Thrive Architect.
*/
public function isBuiltWith( $postId ) {
if ( ! function_exists( 'tcb_post' ) ) {
return false;
}
return tcb_post( $postId )->editor_enabled();
}
/**
* Returns whether should or not limit the modified date.
*
* @since 4.6.6
*
* @param int $postId The Post ID.
* @return boolean Whether or not sholud limit the modified date.
*/
public function limitModifiedDate( $postId ) {
if ( ! class_exists( 'TCB_Editor_Ajax' ) ) {
return false;
}
// This method is supposed to be used in the `wp_ajax_tcb_editor_ajax` action.
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), \TCB_Editor_Ajax::NONCE_KEY ) ) {
return false;
}
$editorPostId = ! empty( $_REQUEST['post_id'] ) ? intval( $_REQUEST['post_id'] ) : 0;
if ( $editorPostId !== $postId ) {
return false;
}
return ! empty( $_REQUEST['aioseo_limit_modified_date'] ) && 'true' === $_REQUEST['aioseo_limit_modified_date'];
}
} PageBuilders/Base.php 0000666 00000012307 15114751622 0010510 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\PageBuilders;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Base class for each of our page builder integrations.
*
* @since 4.1.7
*/
abstract class Base {
/**
* The plugin files we can integrate with.
*
* @since 4.1.7
*
* @var array
*/
public $plugins = [];
/**
* The themes names we can integrate with.
*
* @since 4.1.7
*
* @var array
*/
public $themes = [];
/**
* The integration slug.
*
* @since 4.1.7
*
* @var string
*/
public $integrationSlug = '';
/**
* Class constructor.
*
* @since 4.1.7
*
* @return void
*/
public function __construct() {
// We need to delay it to give other plugins a chance to register custom post types.
add_action( 'init', [ $this, '_init' ], PHP_INT_MAX );
}
/**
* The internal init function.
*
* @since 4.1.7
*
* @return void
*/
public function _init() {
// Check if we do have an integration slug.
if ( empty( $this->integrationSlug ) ) {
return;
}
// Check if the plugin or theme to integrate with is active.
if ( ! $this->isPluginActive() && ! $this->isThemeActive() ) {
return;
}
// Check if we can proceed with the integration.
if ( apply_filters( 'aioseo_page_builder_integration_disable', false, $this->integrationSlug ) ) {
return;
}
$this->init();
}
/**
* The init function.
*
* @since 4.1.7
*
* @return void
*/
public function init() {}
/**
* Check if the integration is active.
*
* @since 4.4.8
*
* @return bool Whether or not the integration is active.
*/
public function isActive() {
return $this->isPluginActive() || $this->isThemeActive();
}
/**
* Check whether or not the plugin is active.
*
* @since 4.1.7
*
* @return bool Whether or not the plugin is active.
*/
public function isPluginActive() {
include_once ABSPATH . 'wp-admin/includes/plugin.php';
$plugins = apply_filters( 'aioseo_page_builder_integration_plugins', $this->plugins, $this->integrationSlug );
foreach ( $plugins as $basename ) {
if ( is_plugin_active( $basename ) ) {
return true;
}
}
return false;
}
/**
* Check whether or not the theme is active.
*
* @since 4.1.7
*
* @return bool Whether or not the theme is active.
*/
public function isThemeActive() {
$themes = apply_filters( 'aioseo_page_builder_integration_themes', $this->themes, $this->integrationSlug );
$theme = wp_get_theme();
foreach ( $themes as $name ) {
if ( $name === $theme->stylesheet || $name === $theme->template ) {
return true;
}
}
return false;
}
/**
* Enqueue the scripts and styles.
*
* @since 4.1.7
*
* @return void
*/
public function enqueue() {
$integrationSlug = $this->integrationSlug;
aioseo()->core->assets->load( "src/vue/standalone/page-builders/$integrationSlug/main.js", [], aioseo()->helpers->getVueData( 'post', $this->getPostId(), $integrationSlug ) );
aioseo()->core->assets->enqueueCss( 'src/vue/assets/scss/integrations/main.scss' );
aioseo()->admin->addAioseoModalPortal();
aioseo()->main->enqueueTranslations();
}
/**
* Get the post ID.
*
* @since 4.1.7
*
* @return int|null The post ID or null.
*/
public function getPostId() {
// phpcs:disable HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
foreach ( [ 'id', 'post', 'post_id' ] as $key ) {
if ( ! empty( $_GET[ $key ] ) ) {
return (int) sanitize_text_field( wp_unslash( $_GET[ $key ] ) );
}
}
// phpcs:enable
if ( ! empty( $GLOBALS['post'] ) ) {
return (int) $GLOBALS['post']->ID;
}
return null;
}
/**
* Returns the page builder edit url for the given Post ID.
*
* @since 4.3.1
*
* @param int $postId The Post ID.
* @return string The Edit URL.
*/
public function getEditUrl( $postId ) { // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
return '';
}
/**
* Returns whether or not the given Post ID was built with the Page Builder.
*
* @since 4.1.7
*
* @param int $postId The Post ID.
* @return boolean Whether or not the Post was built with the Page Builder.
*/
public function isBuiltWith( $postId ) { // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
return false;
}
/**
* Checks whether or not we should prevent the date from being modified.
*
* @since 4.5.2
*
* @param int $postId The Post ID.
* @return bool Whether or not we should prevent the date from being modified.
*/
public function limitModifiedDate( $postId ) { // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
return false;
}
/**
* Returns the processed page builder content.
*
* @since 4.5.2
*
* @param int $postId The post id.
* @param string $content The raw content.
* @return string The processed content.
*/
public function processContent( $postId, $content = '' ) {
if ( empty( $content ) ) {
$post = get_post( $postId );
if ( is_a( $post, 'WP_Post' ) ) {
$content = $post->post_content;
}
}
if ( aioseo()->helpers->isAjaxCronRestRequest() ) {
return apply_filters( 'the_content', $content );
}
return $content;
}
} PageBuilders/WPBakery.php 0000666 00000006772 15114751622 0011333 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\PageBuilders;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Integrate our SEO Panel with WPBakery Page Builder.
*
* @since 4.5.2
*/
class WPBakery extends Base {
/**
* The plugin files.
*
* @since 4.5.2
*
* @var array
*/
public $plugins = [
'js_composer/js_composer.php',
'js_composer_salient/js_composer.php'
];
/**
* The integration slug.
*
* @since 4.5.2
*
* @var string
*/
public $integrationSlug = 'wpbakery';
/**
* Init the integration.
*
* @since 4.5.2
*
* @return void
*/
public function init() {
// Disable SEO meta tags from WP Bakery.
if ( defined( 'WPB_VC_VERSION' ) && version_compare( WPB_VC_VERSION, '7.4', '>=' ) ) {
add_filter( 'get_post_metadata', [ $this, 'maybeDisableWpBakeryMetaTags' ], 10, 3 );
}
if ( ! aioseo()->postSettings->canAddPostSettingsMetabox( get_post_type( $this->getPostId() ) ) ) {
return;
}
add_action( 'vc_frontend_editor_enqueue_js_css', [ $this, 'enqueue' ] );
add_action( 'vc_backend_editor_enqueue_js_css', [ $this, 'enqueue' ] );
add_filter( 'vc_nav_front_controls', [ $this, 'addNavbarCotnrols' ] );
add_filter( 'vc_nav_controls', [ $this, 'addNavbarCotnrols' ] );
}
/**
* Maybe disable WP Bakery meta tags.
*
* @since 4.7.1
*
* @param mixed $value The value of the meta.
* @param int $objectId The object ID.
* @param string $metaKey The meta key.
* @return mixed The value of the meta.
*/
public function maybeDisableWpBakeryMetaTags( $value, $objectId, $metaKey ) {
if ( is_singular() && '_wpb_post_custom_seo_settings' === $metaKey ) {
return null;
}
return $value;
}
public function addNavbarCotnrols( $controlList ) {
$controlList[] = [
'aioseo',
'<li class="vc_show-mobile"><div id="aioseo-wpbakery" style="height: 100%;"></div></li>'
];
return $controlList;
}
/**
* Returns whether or not the given Post ID was built with WPBakery.
*
* @since 4.5.2
*
* @param int $postId The Post ID.
* @return boolean Whether or not the Post was built with WPBakery.
*/
public function isBuiltWith( $postId ) {
$postObj = get_post( $postId );
if ( ! empty( $postObj ) && preg_match( '/vc_row/', (string) $postObj->post_content ) ) {
return true;
}
return false;
}
/**
* Returns whether should or not limit the modified date.
*
* @since 4.5.2
*
* @param int $postId The Post ID.
* @return boolean Whether or not sholud limit the modified date.
*/
public function limitModifiedDate( $postId ) {
// This method is supposed to be used in the `saveAjaxFe` action.
if ( empty( $_REQUEST['_vcnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_vcnonce'] ) ), 'vc-nonce-vc-admin-nonce' ) ) {
return false;
}
$editorPostId = ! empty( $_REQUEST['post_id'] ) ? intval( $_REQUEST['post_id'] ) : 0;
if ( $editorPostId !== $postId ) {
return false;
}
return ! empty( $_REQUEST['aioseo_limit_modified_date'] ) && (bool) $_REQUEST['aioseo_limit_modified_date'];
}
/**
* Returns the processed page builder content.
*
* @since 4.5.2
*
* @param int $postId The post id.
* @param string $content The raw content.
* @return string The processed content.
*/
public function processContent( $postId, $content = '' ) {
if ( method_exists( '\WPBMap', 'addAllMappedShortcodes' ) ) {
\WPBMap::addAllMappedShortcodes();
}
return parent::processContent( $postId, $content );
}
} PageBuilders/Divi.php 0000666 00000012577 15114751622 0010542 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\PageBuilders;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Integrate our SEO Panel with Divi Page Builder.
*
* @since 4.1.7
*/
class Divi extends Base {
/**
* The theme name.
*
* @since 4.1.7
*
* @var array
*/
public $themes = [ 'Divi', 'Extra' ];
/**
* The plugin files.
*
* @since 4.2.0
*
* @var array
*/
public $plugins = [
'divi-builder/divi-builder.php'
];
/**
* The integration slug.
*
* @since 4.1.7
*
* @var string
*/
public $integrationSlug = 'divi';
/**
* Init the integration.
*
* @since 4.1.7
*
* @return void
*/
public function init() {
add_action( 'wp', [ $this, 'maybeRun' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueueAdmin' ] );
}
/**
* Check if we are in the Page Builder and run the integrations.
*
* @since 4.1.7
*
* @return void
*/
public function maybeRun() {
$postType = get_post_type( $this->getPostId() );
if (
! defined( 'ET_BUILDER_PRODUCT_VERSION' ) ||
! version_compare( '4.9.2', ET_BUILDER_PRODUCT_VERSION, '<=' ) ||
! ( function_exists( 'et_core_is_fb_enabled' ) && et_core_is_fb_enabled() ) ||
! aioseo()->postSettings->canAddPostSettingsMetabox( $postType )
) {
return;
}
add_action( 'wp_footer', [ $this, 'addContainers' ] );
add_action( 'wp_footer', [ $this, 'addIframeWatcher' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue' ] );
add_filter( 'script_loader_tag', [ $this, 'addEtTag' ], 10, 2 );
}
/**
* Enqueue the required scripts for the admin screen.
*
* @since 4.1.7
*
* @return void
*/
public function enqueueAdmin() {
if ( ! aioseo()->helpers->isScreenBase( 'toplevel_page_et_divi_options' ) ) {
return;
}
aioseo()->core->assets->load( 'src/vue/standalone/page-builders/divi-admin/main.js', [], aioseo()->helpers->getVueData() );
aioseo()->main->enqueueTranslations();
}
/**
* Add et attributes to script tags.
*
* @since 4.1.7
*
* @param string $tag The <script> tag for the enqueued script.
* @param string $handle The script's registered handle.
* @return string The tag.
*/
public function addEtTag( $tag, $handle = '' ) {
$scriptHandles = [
'aioseo/js/src/vue/standalone/page-builders/divi/main.js',
'aioseo/js/src/vue/standalone/app/main.js'
];
if ( in_array( $handle, $scriptHandles, true ) ) {
// These tags load in parent window only, not in Divi iframe.
return preg_replace( '/<script/', '<script class="et_fb_ignore_iframe"', (string) $tag );
}
return $tag;
}
/**
* Add the Divi watcher.
*
* @since 4.1.7
*
* @return void
*/
public function addIframeWatcher() {
?>
<script type="text/javascript">
if (typeof jQuery === 'function') {
jQuery(window).on('et_builder_api_ready et_fb_section_content_change', function(event) {
window.parent.postMessage({ eventType : event.type })
})
}
</script>
<?php
}
/**
* Add the containers to mount our panel.
*
* @since 4.1.7
*
* @return void
*/
public function addContainers() {
echo '<div id="aioseo-app-modal" class="et_fb_ignore_iframe"><div class="et_fb_ignore_iframe"></div></div>';
echo '<div id="aioseo-settings" class="et_fb_ignore_iframe"></div>';
echo '<div id="aioseo-admin" class="et_fb_ignore_iframe"></div>';
echo '<div id="aioseo-modal-portal" class="et_fb_ignore_iframe"></div>';
}
/**
* Returns whether or not the given Post ID was built with Divi.
*
* @since 4.1.7
*
* @param int $postId The Post ID.
* @return boolean Whether or not the Post was built with Divi.
*/
public function isBuiltWith( $postId ) {
if ( ! function_exists( 'et_pb_is_pagebuilder_used' ) ) {
return false;
}
return et_pb_is_pagebuilder_used( $postId );
}
/**
* Returns the Divi edit url for the given Post ID.
*
* @since 4.3.1
*
* @param int $postId The Post ID.
* @return string The Edit URL.
*/
public function getEditUrl( $postId ) {
if ( ! function_exists( 'et_fb_get_vb_url' ) ) {
return '';
}
$isDiviLibrary = 'et_pb_layout' === get_post_type( $postId );
$editUrl = $isDiviLibrary ? get_edit_post_link( $postId, 'raw' ) : get_permalink( $postId );
if ( et_pb_is_pagebuilder_used( $postId ) ) {
$editUrl = et_fb_get_vb_url( $editUrl );
} else {
if ( ! et_pb_is_allowed( 'divi_builder_control' ) ) {
// Prevent link when user lacks `Toggle Divi Builder` capability.
return '';
}
$editUrl = add_query_arg(
[ 'et_fb_activation_nonce' => wp_create_nonce( 'et_fb_activation_nonce_' . $postId ) ],
$editUrl
);
}
return $editUrl;
}
/**
* Checks whether or not we should prevent the date from being modified.
*
* @since 4.5.2
*
* @param int $postId The Post ID.
* @return bool Whether or not we should prevent the date from being modified.
*/
public function limitModifiedDate( $postId ) {
// This method is supposed to be used in the `wp_ajax_et_fb_ajax_save` action.
if ( empty( $_REQUEST['et_fb_save_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['et_fb_save_nonce'] ) ), 'et_fb_save_nonce' ) ) {
return false;
}
$editorPostId = ! empty( $_REQUEST['post_id'] ) ? intval( $_REQUEST['post_id'] ) : 0;
if ( $editorPostId !== $postId ) {
return false;
}
return ! empty( $_REQUEST['options']['conditional_tags']['aioseo_limit_modified_date'] );
}
} PageBuilders/SiteOrigin.php 0000666 00000005157 15114751622 0011717 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\PageBuilders;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Integrate our SEO Panel with SiteOrigin Page Builder.
*
* @since 4.6.6
*/
class SiteOrigin extends Base {
/**
* The plugin files.
*
* @since 4.6.6
*
* @var array
*/
public $plugins = [
'siteorigin-panels/siteorigin-panels.php'
];
/**
* The integration slug.
*
* @since 4.6.6
*
* @var string
*/
public $integrationSlug = 'siteorigin';
/**
* Init the integration.
*
* @since 4.6.6
*
* @return void
*/
public function init() {
$postType = get_post_type( $this->getPostId() );
if ( empty( $postType ) ) {
$postType = ! empty( $_GET['post_type'] ) ? sanitize_text_field( wp_unslash( $_GET['post_type'] ) ) : 'post'; // phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended, Generic.Files.LineLength.MaxExceeded
}
if ( ! aioseo()->postSettings->canAddPostSettingsMetabox( $postType ) ) {
return;
}
add_action( 'siteorigin_panel_enqueue_admin_scripts', [ $this, 'enqueue' ] );
}
/**
* Returns whether or not the given Post ID was built with SiteOrigin.
*
* @since 4.6.6
*
* @param int $postId The Post ID.
* @return bool Whether or not the Post was built with SiteOrigin.
*/
public function isBuiltWith( $postId ) {
$postObj = get_post( $postId );
if (
! empty( $postObj ) &&
(
preg_match( '/siteorigin_widget/', (string) $postObj->post_content ) ||
preg_match( '/so-panel widget/', (string) $postObj->post_content )
)
) {
return true;
}
return false;
}
/**
* Returns the processed page builder content.
*
* @since 4.6.6
*
* @param int $postId The post id.
* @param string $content The raw content.
* @return string The processed content.
*/
public function processContent( $postId, $content = '' ) {
// When performing a save_post action, we must execute the siteorigin_widget shortcodes if there are image widgets.
// This ensures that the getFirstImageInContent method can locate the images, as SiteOrigin uses shortcodes for images.
// We cache the first image in the content during post saving.
if (
doing_action( 'save_post' ) &&
aioseo()->options->searchAppearance->advanced->runShortcodes &&
(
stripos( $content, 'SiteOrigin_Widget_Image_Widget' ) !== false ||
stripos( $content, 'WP_Widget_Media_Image' ) !== false
)
) {
$content = aioseo()->helpers->doAllowedShortcodes( $content, $postId, [ 'siteorigin_widget' ] );
}
return parent::processContent( $postId, $content );
}
} PageBuilders/Elementor.php 0000666 00000013656 15114751622 0011600 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Standalone\PageBuilders;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use Elementor\Controls_Manager as ControlsManager;
use Elementor\Core\DocumentTypes\PageBase;
/**
* Integrate our SEO Panel with Elementor Page Builder.
*
* @since 4.1.7
*/
class Elementor extends Base {
/**
* The plugin files.
*
* @since 4.1.7
*
* @var array
*/
public $plugins = [
'elementor/elementor.php',
'elementor-pro/elementor-pro.php',
];
/**
* The integration slug.
*
* @since 4.1.7
*
* @var string
*/
public $integrationSlug = 'elementor';
/**
* Init the integration.
*
* @since 4.1.7
*
* @return void
*/
public function init() {
if ( ! aioseo()->postSettings->canAddPostSettingsMetabox( get_post_type( $this->getPostId() ) ) ) {
return;
}
if ( ! did_action( 'elementor/init' ) ) {
add_action( 'elementor/init', [ $this, 'addPanelTab' ] );
} else {
$this->addPanelTab();
}
add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'enqueue' ] );
add_action( 'elementor/documents/register_controls', [ $this, 'registerDocumentControls' ] );
add_action( 'elementor/editor/footer', [ $this, 'addContainers' ] );
// Add the SEO tab to the main Elementor panel.
add_action( 'elementor/editor/footer', [ $this, 'startCapturing' ], 0 );
add_action( 'elementor/editor/footer', [ $this, 'endCapturing' ], 999 );
}
/**
* Start capturing buffer.
*
* @since 4.3.5
*
* @return void
*/
public function startCapturing() {
ob_start();
}
/**
* End capturing buffer and add button.
* This is a hack to add the SEO tab to the main Elementor panel.
* We need to do this because Elementor doesn't provide a filter to add tabs to the main panel.
*
* @since 4.3.5
*
* @return void
*/
public function endCapturing() {
$output = ob_get_clean();
$search = '/(<div class="elementor-component-tab elementor-panel-navigation-tab" data-tab="global">.*<\/div>)/m';
$replace = '${1}<div class="elementor-component-tab elementor-panel-navigation-tab" data-tab="aioseo">SEO</div>';
echo preg_replace( $search, $replace, $output ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* Add the AIOSEO Panel Tab on Elementor.
*
* @since 4.1.7
*
* @return void
*/
public function addPanelTab() {
ControlsManager::add_tab( 'aioseo', AIOSEO_PLUGIN_SHORT_NAME );
}
/**
* Register the Elementor Document Controls.
*
* @since 4.1.7
*
* @return void
*/
public function registerDocumentControls( $document ) {
// PageBase is the base class for documents like `post` `page` and etc.
if ( ! $document instanceof PageBase || ! $document::get_property( 'has_elements' ) ) {
return;
}
// This is needed to get the tab to appear, but will be overwritten in the JavaScript.
$document->start_controls_section(
'aioseo_section',
[
'label' => AIOSEO_PLUGIN_SHORT_NAME,
'tab' => 'aioseo',
]
);
$document->end_controls_section();
}
/**
* Returns whether or not the given Post ID was built with Elementor.
*
* @since 4.1.7
*
* @param int $postId The Post ID.
* @return boolean Whether or not the Post was built with Elementor.
*/
public function isBuiltWith( $postId ) {
$document = $this->getElementorDocument( $postId );
if ( ! $document ) {
return false;
}
return $document->is_built_with_elementor();
}
/**
* Returns the Elementor edit url for the given Post ID.
*
* @since 4.3.1
*
* @param int $postId The Post ID.
* @return string The Edit URL.
*/
public function getEditUrl( $postId ) {
$document = $this->getElementorDocument( $postId );
if ( ! $document || ! $document->is_editable_by_current_user() ) {
return '';
}
return esc_url( $document->get_edit_url() );
}
/**
* Add the containers to mount our panel.
*
* @since 4.1.9
*
* @return void
*/
public function addContainers() {
echo '<div id="aioseo-admin"></div>';
}
/**
* Returns the Elementor Document instance for the given Post ID.
*
* @since 4.3.5
*
* @param int $postId The Post ID.
* @return object The Elementor Document instance.
*/
private function getElementorDocument( $postId ) {
if (
! class_exists( '\Elementor\Plugin' ) ||
! is_object( \Elementor\Plugin::instance()->documents ) ||
! method_exists( \Elementor\Plugin::instance()->documents, 'get' )
) {
return false;
}
$elementorDocument = \Elementor\Plugin::instance()->documents->get( $postId );
if ( empty( $elementorDocument ) ) {
return false;
}
return $elementorDocument;
}
/**
* Checks whether or not we should prevent the date from being modified.
* This method is supposed to be used in the `wp_ajax_seedprod_pro_save_lpage` action.
*
* @since 4.5.2
*
* @param int $postId The Post ID.
* @return bool Whether or not we should prevent the date from being modified.
*/
public function limitModifiedDate( $postId ) {
// This method is supposed to be used in the `wp_ajax_elementor_ajax` action.
if ( empty( $_REQUEST['_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_nonce'] ) ), 'elementor_ajax' ) ) {
return false;
}
$editorPostId = ! empty( $_REQUEST['editor_post_id'] ) ? (int) $_REQUEST['editor_post_id'] : false;
if ( $editorPostId !== $postId ) {
return false;
}
return ! empty( $_REQUEST['aioseo_limit_modified_date'] );
}
/**
* Get the post ID.
*
* @since 4.6.9
*
* @return int|null The post ID or null.
*/
public function getPostId() {
// phpcs:disable HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
if ( aioseo()->helpers->isAjaxCronRestRequest() ) {
foreach ( [ 'editor_post_id', 'initial_document_id' ] as $key ) {
if ( ! empty( $_REQUEST[ $key ] ) ) {
return intval( wp_unslash( $_REQUEST[ $key ] ) );
}
}
}
// phpcs:enable
return parent::getPostId();
}
}