| Current Path : /home/x/b/o/xbodynamge/namtation/wp-content/ |
| Current File : /home/x/b/o/xbodynamge/namtation/wp-content/Options.php.tar |
home/xbodynamge/dev/wp-content/plugins/all-in-one-seo-pack/app/Lite/Traits/Options.php 0000644 00000005230 15114102207 0024701 0 ustar 00 <?php
namespace AIOSEO\Plugin\Lite\Traits;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Options trait.
*
* @since 4.0.0
*/
trait Options {
/**
* Initialize the options.
*
* @since 4.1.4
*
* @return void
*/
public function init() {
parent::init();
$dbOptions = $this->getDbOptions( $this->optionsName . '_lite' );
// Refactor options.
$this->defaultsMerged = array_replace_recursive( $this->defaults, $this->liteDefaults );
$mergedDefaults = array_replace_recursive(
$this->liteDefaults,
$this->addValueToValuesArray( $this->liteDefaults, $dbOptions )
);
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$dbOptions = array_replace_recursive(
$cachedOptions,
$mergedDefaults
);
aioseo()->core->optionsCache->setOptions( $this->optionsName, $dbOptions );
}
/**
* Merge defaults with liteDefaults.
*
* @since 4.1.4
*
* @return array An array of dafults.
*/
public function getDefaults() {
return array_replace_recursive( parent::getDefaults(), $this->liteDefaults );
}
/**
* Updates the options in the database.
*
* @since 4.1.4
*
* @param string $optionsName An optional option name to update.
* @param string $defaults The defaults to filter the options by.
* @param array|null $options An optional options array.
* @return void
*/
public function update( $optionsName = null, $defaults = null, $options = null ) {
$optionsName = empty( $optionsName ) ? $this->optionsName . '_lite' : $optionsName;
$defaults = empty( $defaults ) ? $this->liteDefaults : $defaults;
// We're creating a new array here because it was setting it by reference.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$optionsBefore = json_decode( wp_json_encode( $cachedOptions ), true );
parent::update( $this->optionsName, $options );
parent::update( $optionsName, $defaults, $optionsBefore );
}
/**
* Updates the options in the database.
*
* @since 4.1.4
*
* @param boolean $force Whether or not to force an immediate save.
* @param string $optionsName An optional option name to update.
* @param string $defaults The defaults to filter the options by.
* @return void
*/
public function save( $force = false, $optionsName = null, $defaults = null ) {
if ( ! $this->shouldSave && ! $force ) {
return;
}
$optionsName = empty( $optionsName ) ? $this->optionsName . '_lite' : $optionsName;
$defaults = empty( $defaults ) ? $this->liteDefaults : $defaults;
parent::save( $force, $this->optionsName );
parent::save( $force, $optionsName, $defaults );
}
} home/xbodynamge/namtation/wp-content/plugins/all-in-one-seo-pack/app/Lite/Traits/Options.php 0000644 00000005230 15114524425 0026127 0 ustar 00 <?php
namespace AIOSEO\Plugin\Lite\Traits;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Options trait.
*
* @since 4.0.0
*/
trait Options {
/**
* Initialize the options.
*
* @since 4.1.4
*
* @return void
*/
public function init() {
parent::init();
$dbOptions = $this->getDbOptions( $this->optionsName . '_lite' );
// Refactor options.
$this->defaultsMerged = array_replace_recursive( $this->defaults, $this->liteDefaults );
$mergedDefaults = array_replace_recursive(
$this->liteDefaults,
$this->addValueToValuesArray( $this->liteDefaults, $dbOptions )
);
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$dbOptions = array_replace_recursive(
$cachedOptions,
$mergedDefaults
);
aioseo()->core->optionsCache->setOptions( $this->optionsName, $dbOptions );
}
/**
* Merge defaults with liteDefaults.
*
* @since 4.1.4
*
* @return array An array of dafults.
*/
public function getDefaults() {
return array_replace_recursive( parent::getDefaults(), $this->liteDefaults );
}
/**
* Updates the options in the database.
*
* @since 4.1.4
*
* @param string $optionsName An optional option name to update.
* @param string $defaults The defaults to filter the options by.
* @param array|null $options An optional options array.
* @return void
*/
public function update( $optionsName = null, $defaults = null, $options = null ) {
$optionsName = empty( $optionsName ) ? $this->optionsName . '_lite' : $optionsName;
$defaults = empty( $defaults ) ? $this->liteDefaults : $defaults;
// We're creating a new array here because it was setting it by reference.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$optionsBefore = json_decode( wp_json_encode( $cachedOptions ), true );
parent::update( $this->optionsName, $options );
parent::update( $optionsName, $defaults, $optionsBefore );
}
/**
* Updates the options in the database.
*
* @since 4.1.4
*
* @param boolean $force Whether or not to force an immediate save.
* @param string $optionsName An optional option name to update.
* @param string $defaults The defaults to filter the options by.
* @return void
*/
public function save( $force = false, $optionsName = null, $defaults = null ) {
if ( ! $this->shouldSave && ! $force ) {
return;
}
$optionsName = empty( $optionsName ) ? $this->optionsName . '_lite' : $optionsName;
$defaults = empty( $defaults ) ? $this->liteDefaults : $defaults;
parent::save( $force, $this->optionsName );
parent::save( $force, $optionsName, $defaults );
}
} home/xbodynamge/dev/wp-content/plugins/all-in-one-seo-pack/app/Lite/Options/Options.php 0000644 00000002371 15114613055 0025101 0 ustar 00 <?php
namespace AIOSEO\Plugin\Lite\Options;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Options as CommonOptions;
use AIOSEO\Plugin\Lite\Traits;
/**
* Class that holds all options for AIOSEO.
*
* @since 4.0.0
*/
class Options extends CommonOptions\Options {
use Traits\Options;
/**
* Defaults options for Lite.
*
* @since 4.0.0
*
* @var array
*/
private $liteDefaults = [
// phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
'advanced' => [
'usageTracking' => [ 'type' => 'boolean', 'default' => false ]
]
// phpcs:enable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
];
/**
* Sanitizes, then saves the options to the database.
*
* @since 4.7.2
*
* @param array $options An array of options to sanitize, then save.
* @return void
*/
public function sanitizeAndSave( $options ) {
if ( isset( $options['advanced']['emailSummary']['recipients'] ) ) {
$options['advanced']['emailSummary']['recipients'] = [ array_shift( $options['advanced']['emailSummary']['recipients'] ) ];
$options['advanced']['emailSummary']['recipients'][0]['frequency'] = 'monthly';
}
parent::sanitizeAndSave( $options );
}
} home/xbodynamge/namtation/wp-content/plugins/all-in-one-seo-pack/app/Common/Options/Options.php 0000644 00000106145 15114636205 0026656 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Options;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
use AIOSEO\Plugin\Common\Traits;
/**
* Class that holds all options for AIOSEO.
*
* @since 4.0.0
*/
class Options {
use Traits\Options;
/**
* All the default options.
*
* @since 4.0.0
*
* @var array
*/
protected $defaults = [
// phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
'internal' => [],
'webmasterTools' => [
'google' => [ 'type' => 'string' ],
'bing' => [ 'type' => 'string' ],
'yandex' => [ 'type' => 'string' ],
'baidu' => [ 'type' => 'string' ],
'pinterest' => [ 'type' => 'string' ],
'microsoftClarityProjectId' => [ 'type' => 'string' ],
'norton' => [ 'type' => 'string' ],
'miscellaneousVerification' => [ 'type' => 'html' ]
],
'breadcrumbs' => [
'separator' => [ 'type' => 'string', 'default' => '»' ],
'homepageLink' => [ 'type' => 'boolean', 'default' => true ],
'homepageLabel' => [ 'type' => 'string', 'default' => 'Home' ],
'breadcrumbPrefix' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'archiveFormat' => [ 'type' => 'string', 'default' => 'Archives for #breadcrumb_archive_post_type_name', 'localized' => true ],
'searchResultFormat' => [ 'type' => 'string', 'default' => 'Search Results for \'#breadcrumb_search_string\'', 'localized' => true ],
'errorFormat404' => [ 'type' => 'string', 'default' => '404 - Page Not Found', 'localized' => true ],
'showCurrentItem' => [ 'type' => 'boolean', 'default' => true ],
'linkCurrentItem' => [ 'type' => 'boolean', 'default' => false ],
'categoryFullHierarchy' => [ 'type' => 'boolean', 'default' => false ],
'showBlogHome' => [ 'type' => 'boolean', 'default' => false ]
],
'rssContent' => [
'before' => [ 'type' => 'html' ],
'after' => [
'type' => 'html',
'default' => <<<TEMPLATE
<p>The post #post_link first appeared on #site_link.</p>
TEMPLATE
]
],
'advanced' => [
'truSeo' => [ 'type' => 'boolean', 'default' => true ],
'headlineAnalyzer' => [ 'type' => 'boolean', 'default' => true ],
'seoAnalysis' => [ 'type' => 'boolean', 'default' => true ],
'dashboardWidgets' => [ 'type' => 'array', 'default' => [ 'seoSetup', 'seoOverview', 'seoNews' ] ],
'announcements' => [ 'type' => 'boolean', 'default' => true ],
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page', 'product' ] ],
],
'taxonomies' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'category', 'post_tag', 'product_cat', 'product_tag' ] ],
],
'uninstall' => [ 'type' => 'boolean', 'default' => false ],
'emailSummary' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'recipients' => [ 'type' => 'array', 'default' => [] ]
]
],
'sitemap' => [
'general' => [
'enable' => [ 'type' => 'boolean', 'default' => true ],
'filename' => [ 'type' => 'string', 'default' => 'sitemap' ],
'indexes' => [ 'type' => 'boolean', 'default' => true ],
'linksPerIndex' => [ 'type' => 'number', 'default' => 1000 ],
// @TODO: [V4+] Convert this to the dynamic options like in search appearance so we can have backups when plugins are deactivated.
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page', 'attachment', 'product' ] ],
],
// @TODO: [V4+] Convert this to the dynamic options like in search appearance so we can have backups when plugins are deactivated.
'taxonomies' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'category', 'post_tag', 'product_cat', 'product_tag' ] ],
],
'author' => [ 'type' => 'boolean', 'default' => false ],
'date' => [ 'type' => 'boolean', 'default' => false ],
'additionalPages' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'pages' => [ 'type' => 'array', 'default' => [] ]
],
'advancedSettings' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'excludeImages' => [ 'type' => 'boolean', 'default' => false ],
'excludePosts' => [ 'type' => 'array', 'default' => [] ],
'excludeTerms' => [ 'type' => 'array', 'default' => [] ],
'priority' => [
'homePage' => [
'priority' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ],
'frequency' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ]
],
'postTypes' => [
'grouped' => [ 'type' => 'boolean', 'default' => true ],
'priority' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ],
'frequency' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ]
],
'taxonomies' => [
'grouped' => [ 'type' => 'boolean', 'default' => true ],
'priority' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ],
'frequency' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ]
],
'archive' => [
'priority' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ],
'frequency' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ]
],
'author' => [
'priority' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ],
'frequency' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ]
]
]
]
],
'rss' => [
'enable' => [ 'type' => 'boolean', 'default' => true ],
'linksPerIndex' => [ 'type' => 'number', 'default' => 50 ],
// @TODO: [V4+] Convert this to the dynamic options like in search appearance so we can have backups when plugins are deactivated.
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page', 'product' ] ],
]
],
'html' => [
'enable' => [ 'type' => 'boolean', 'default' => true ],
'pageUrl' => [ 'type' => 'string', 'default' => '' ],
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page', 'product' ] ],
],
'taxonomies' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'category', 'post_tag', 'product_cat', 'product_tag' ] ],
],
'sortOrder' => [ 'type' => 'string', 'default' => 'publish_date' ],
'sortDirection' => [ 'type' => 'string', 'default' => 'asc' ],
'publicationDate' => [ 'type' => 'boolean', 'default' => true ],
'compactArchives' => [ 'type' => 'boolean', 'default' => false ],
'advancedSettings' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'nofollowLinks' => [ 'type' => 'boolean', 'default' => false ],
'excludePosts' => [ 'type' => 'array', 'default' => [] ],
'excludeTerms' => [ 'type' => 'array', 'default' => [] ]
]
],
],
'social' => [
'profiles' => [
'sameUsername' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'username' => [ 'type' => 'string' ],
'included' => [ 'type' => 'array', 'default' => [ 'facebookPageUrl', 'twitterUrl', 'tiktokUrl', 'pinterestUrl', 'instagramUrl', 'youtubeUrl', 'linkedinUrl' ] ]
],
'urls' => [
'facebookPageUrl' => [ 'type' => 'string' ],
'twitterUrl' => [ 'type' => 'string' ],
'instagramUrl' => [ 'type' => 'string' ],
'tiktokUrl' => [ 'type' => 'string' ],
'pinterestUrl' => [ 'type' => 'string' ],
'youtubeUrl' => [ 'type' => 'string' ],
'linkedinUrl' => [ 'type' => 'string' ],
'tumblrUrl' => [ 'type' => 'string' ],
'yelpPageUrl' => [ 'type' => 'string' ],
'soundCloudUrl' => [ 'type' => 'string' ],
'wikipediaUrl' => [ 'type' => 'string' ],
'myspaceUrl' => [ 'type' => 'string' ],
'googlePlacesUrl' => [ 'type' => 'string' ],
'wordPressUrl' => [ 'type' => 'string' ],
'blueskyUrl' => [ 'type' => 'string' ],
'threadsUrl' => [ 'type' => 'string' ]
],
'additionalUrls' => [ 'type' => 'string' ]
],
'facebook' => [
'general' => [
'enable' => [ 'type' => 'boolean', 'default' => true ],
'defaultImageSourcePosts' => [ 'type' => 'string', 'default' => 'default' ],
'customFieldImagePosts' => [ 'type' => 'string' ],
'defaultImagePosts' => [ 'type' => 'string', 'default' => '' ],
'defaultImagePostsWidth' => [ 'type' => 'number', 'default' => '' ],
'defaultImagePostsHeight' => [ 'type' => 'number', 'default' => '' ],
'showAuthor' => [ 'type' => 'boolean', 'default' => true ],
'siteName' => [ 'type' => 'string', 'localized' => true, 'default' => '#site_title #separator_sa #tagline' ]
],
'homePage' => [
'image' => [ 'type' => 'string', 'default' => '' ],
'title' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'description' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'imageWidth' => [ 'type' => 'number', 'default' => '' ],
'imageHeight' => [ 'type' => 'number', 'default' => '' ],
'objectType' => [ 'type' => 'string', 'default' => 'website' ]
],
'advanced' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'adminId' => [ 'type' => 'string', 'default' => '' ],
'appId' => [ 'type' => 'string', 'default' => '' ],
'authorUrl' => [ 'type' => 'string', 'default' => '' ],
'generateArticleTags' => [ 'type' => 'boolean', 'default' => false ],
'useKeywordsInTags' => [ 'type' => 'boolean', 'default' => true ],
'useCategoriesInTags' => [ 'type' => 'boolean', 'default' => true ],
'usePostTagsInTags' => [ 'type' => 'boolean', 'default' => true ]
]
],
'twitter' => [
'general' => [
'enable' => [ 'type' => 'boolean', 'default' => true ],
'useOgData' => [ 'type' => 'boolean', 'default' => true ],
'defaultCardType' => [ 'type' => 'string', 'default' => 'summary_large_image' ],
'defaultImageSourcePosts' => [ 'type' => 'string', 'default' => 'default' ],
'customFieldImagePosts' => [ 'type' => 'string' ],
'defaultImagePosts' => [ 'type' => 'string', 'default' => '' ],
'showAuthor' => [ 'type' => 'boolean', 'default' => true ],
'additionalData' => [ 'type' => 'boolean', 'default' => false ]
],
'homePage' => [
'image' => [ 'type' => 'string', 'default' => '' ],
'title' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'description' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'cardType' => [ 'type' => 'string', 'default' => 'summary' ]
],
]
],
'searchAppearance' => [
'global' => [
'separator' => [ 'type' => 'string', 'default' => '-' ],
'siteTitle' => [ 'type' => 'string', 'localized' => true, 'default' => '#site_title #separator_sa #tagline' ],
'metaDescription' => [ 'type' => 'string', 'localized' => true, 'default' => '#tagline' ],
'keywords' => [ 'type' => 'string', 'localized' => true ],
'schema' => [
'websiteName' => [ 'type' => 'string', 'default' => '#site_title' ],
'websiteAlternateName' => [ 'type' => 'string' ],
'siteRepresents' => [ 'type' => 'string', 'default' => 'organization' ],
'person' => [ 'type' => 'string' ],
'organizationName' => [ 'type' => 'string', 'default' => '#site_title' ],
'organizationDescription' => [ 'type' => 'string', 'default' => '#tagline' ],
'organizationLogo' => [ 'type' => 'string' ],
'personName' => [ 'type' => 'string' ],
'personLogo' => [ 'type' => 'string' ],
'phone' => [ 'type' => 'string' ],
'email' => [ 'type' => 'string' ],
'foundingDate' => [ 'type' => 'string' ],
'numberOfEmployees' => [
'isRange' => [ 'type' => 'boolean' ],
'from' => [ 'type' => 'number' ],
'to' => [ 'type' => 'number' ],
'number' => [ 'type' => 'number' ]
]
]
],
'advanced' => [
'globalRobotsMeta' => [
'default' => [ 'type' => 'boolean', 'default' => true ],
'noindex' => [ 'type' => 'boolean', 'default' => false ],
'nofollow' => [ 'type' => 'boolean', 'default' => false ],
'noindexPaginated' => [ 'type' => 'boolean', 'default' => true ],
'nofollowPaginated' => [ 'type' => 'boolean', 'default' => true ],
'noindexFeed' => [ 'type' => 'boolean', 'default' => true ],
'noarchive' => [ 'type' => 'boolean', 'default' => false ],
'noimageindex' => [ 'type' => 'boolean', 'default' => false ],
'notranslate' => [ 'type' => 'boolean', 'default' => false ],
'nosnippet' => [ 'type' => 'boolean', 'default' => false ],
'noodp' => [ 'type' => 'boolean', 'default' => false ],
'maxSnippet' => [ 'type' => 'number', 'default' => -1 ],
'maxVideoPreview' => [ 'type' => 'number', 'default' => -1 ],
'maxImagePreview' => [ 'type' => 'string', 'default' => 'large' ]
],
'noIndexEmptyCat' => [ 'type' => 'boolean', 'default' => true ],
'removeStopWords' => [ 'type' => 'boolean', 'default' => false ],
'useKeywords' => [ 'type' => 'boolean', 'default' => false ],
'keywordsLooking' => [ 'type' => 'boolean', 'default' => true ],
'useCategoriesForMetaKeywords' => [ 'type' => 'boolean', 'default' => false ],
'useTagsForMetaKeywords' => [ 'type' => 'boolean', 'default' => false ],
'dynamicallyGenerateKeywords' => [ 'type' => 'boolean', 'default' => false ],
'pagedFormat' => [ 'type' => 'string', 'default' => '#separator_sa Page #page_number', 'localized' => true ],
'runShortcodes' => [ 'type' => 'boolean', 'default' => false ],
'crawlCleanup' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'feeds' => [
'global' => [ 'type' => 'boolean', 'default' => true ],
'globalComments' => [ 'type' => 'boolean', 'default' => false ],
'staticBlogPage' => [ 'type' => 'boolean', 'default' => true ],
'authors' => [ 'type' => 'boolean', 'default' => true ],
'postComments' => [ 'type' => 'boolean', 'default' => false ],
'search' => [ 'type' => 'boolean', 'default' => false ],
'attachments' => [ 'type' => 'boolean', 'default' => false ],
'archives' => [
'all' => [ 'type' => 'boolean', 'default' => false ],
'included' => [ 'type' => 'array', 'default' => [] ],
],
'taxonomies' => [
'all' => [ 'type' => 'boolean', 'default' => false ],
'included' => [ 'type' => 'array', 'default' => [ 'category' ] ],
],
'atom' => [ 'type' => 'boolean', 'default' => false ],
'rdf' => [ 'type' => 'boolean', 'default' => false ],
'paginated' => [ 'type' => 'boolean', 'default' => false ]
]
],
'unwantedBots' => [
'all' => [ 'type' => 'boolean', 'default' => false ],
'settings' => [
'googleAdsBot' => [ 'type' => 'boolean', 'default' => false ],
'openAiGptBot' => [ 'type' => 'boolean', 'default' => false ],
'commonCrawlCcBot' => [ 'type' => 'boolean', 'default' => false ],
'googleGeminiVertexAiBots' => [ 'type' => 'boolean', 'default' => false ]
]
],
'searchCleanup' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'settings' => [
'maxAllowedNumberOfChars' => [ 'type' => 'number', 'default' => 50 ],
'emojisAndSymbols' => [ 'type' => 'boolean', 'default' => false ],
'commonPatterns' => [ 'type' => 'boolean', 'default' => false ],
'redirectPrettyUrls' => [ 'type' => 'boolean', 'default' => false ],
'preventCrawling' => [ 'type' => 'boolean', 'default' => false ]
]
],
'blockArgs' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'optimizeUtmParameters' => [ 'type' => 'boolean', 'default' => false ],
'logsRetention' => [ 'type' => 'string', 'default' => '{"label":"1 week","value":"week"}' ]
],
'removeCategoryBase' => [ 'type' => 'boolean', 'default' => false ]
],
'archives' => [
'author' => [
'show' => [ 'type' => 'boolean', 'default' => true ],
'title' => [ 'type' => 'string', 'localized' => true, 'default' => '#author_name #separator_sa #site_title' ],
'metaDescription' => [ 'type' => 'string', 'localized' => true, 'default' => '#author_bio' ],
'advanced' => [
'robotsMeta' => [
'default' => [ 'type' => 'boolean', 'default' => true ],
'noindex' => [ 'type' => 'boolean', 'default' => false ],
'nofollow' => [ 'type' => 'boolean', 'default' => false ],
'noarchive' => [ 'type' => 'boolean', 'default' => false ],
'noimageindex' => [ 'type' => 'boolean', 'default' => false ],
'notranslate' => [ 'type' => 'boolean', 'default' => false ],
'nosnippet' => [ 'type' => 'boolean', 'default' => false ],
'noodp' => [ 'type' => 'boolean', 'default' => false ],
'maxSnippet' => [ 'type' => 'number', 'default' => -1 ],
'maxVideoPreview' => [ 'type' => 'number', 'default' => -1 ],
'maxImagePreview' => [ 'type' => 'string', 'default' => 'large' ]
],
'showDateInGooglePreview' => [ 'type' => 'boolean', 'default' => true ],
'showPostThumbnailInSearch' => [ 'type' => 'boolean', 'default' => true ],
'showMetaBox' => [ 'type' => 'boolean', 'default' => true ],
'keywords' => [ 'type' => 'string', 'localized' => true ]
]
],
'date' => [
'show' => [ 'type' => 'boolean', 'default' => true ],
'title' => [ 'type' => 'string', 'localized' => true, 'default' => '#archive_date #separator_sa #site_title' ],
'metaDescription' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'advanced' => [
'robotsMeta' => [
'default' => [ 'type' => 'boolean', 'default' => true ],
'noindex' => [ 'type' => 'boolean', 'default' => false ],
'nofollow' => [ 'type' => 'boolean', 'default' => false ],
'noarchive' => [ 'type' => 'boolean', 'default' => false ],
'noimageindex' => [ 'type' => 'boolean', 'default' => false ],
'notranslate' => [ 'type' => 'boolean', 'default' => false ],
'nosnippet' => [ 'type' => 'boolean', 'default' => false ],
'noodp' => [ 'type' => 'boolean', 'default' => false ],
'maxSnippet' => [ 'type' => 'number', 'default' => -1 ],
'maxVideoPreview' => [ 'type' => 'number', 'default' => -1 ],
'maxImagePreview' => [ 'type' => 'string', 'default' => 'large' ]
],
'showDateInGooglePreview' => [ 'type' => 'boolean', 'default' => true ],
'showPostThumbnailInSearch' => [ 'type' => 'boolean', 'default' => true ],
'showMetaBox' => [ 'type' => 'boolean', 'default' => true ],
'keywords' => [ 'type' => 'string', 'localized' => true ]
]
],
'search' => [
'show' => [ 'type' => 'boolean', 'default' => false ],
'title' => [ 'type' => 'string', 'localized' => true, 'default' => '#search_term #separator_sa #site_title' ],
'metaDescription' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'advanced' => [
'robotsMeta' => [
'default' => [ 'type' => 'boolean', 'default' => false ],
'noindex' => [ 'type' => 'boolean', 'default' => true ],
'nofollow' => [ 'type' => 'boolean', 'default' => false ],
'noarchive' => [ 'type' => 'boolean', 'default' => false ],
'noimageindex' => [ 'type' => 'boolean', 'default' => false ],
'notranslate' => [ 'type' => 'boolean', 'default' => false ],
'nosnippet' => [ 'type' => 'boolean', 'default' => false ],
'noodp' => [ 'type' => 'boolean', 'default' => false ],
'maxSnippet' => [ 'type' => 'number', 'default' => -1 ],
'maxVideoPreview' => [ 'type' => 'number', 'default' => -1 ],
'maxImagePreview' => [ 'type' => 'string', 'default' => 'large' ]
],
'showDateInGooglePreview' => [ 'type' => 'boolean', 'default' => true ],
'showPostThumbnailInSearch' => [ 'type' => 'boolean', 'default' => true ],
'showMetaBox' => [ 'type' => 'boolean', 'default' => true ],
'keywords' => [ 'type' => 'string', 'localized' => true ]
]
]
]
],
'searchStatistics' => [
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page' ] ],
]
],
'tools' => [
'robots' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'rules' => [ 'type' => 'array', 'default' => [] ],
'robotsDetected' => [ 'type' => 'boolean', 'default' => true ],
],
'importExport' => [
'backup' => [
'lastTime' => [ 'type' => 'string' ],
'data' => [ 'type' => 'string' ],
]
]
],
'deprecated' => [
'breadcrumbs' => [
'enable' => [ 'type' => 'boolean', 'default' => true ]
],
'searchAppearance' => [
'global' => [
'descriptionFormat' => [ 'type' => 'string' ],
'schema' => [
'enableSchemaMarkup' => [ 'type' => 'boolean', 'default' => true ]
]
],
'advanced' => [
'autogenerateDescriptions' => [ 'type' => 'boolean', 'default' => true ],
'runShortcodesInDescription' => [ 'type' => 'boolean', 'default' => true ], // TODO: Remove this in a future update.
'useContentForAutogeneratedDescriptions' => [ 'type' => 'boolean', 'default' => false ],
'excludePosts' => [ 'type' => 'array', 'default' => [] ],
'excludeTerms' => [ 'type' => 'array', 'default' => [] ],
'noPaginationForCanonical' => [ 'type' => 'boolean', 'default' => true ]
]
],
'sitemap' => [
'general' => [
'advancedSettings' => [
'dynamic' => [ 'type' => 'boolean', 'default' => true ]
]
]
]
],
'writingAssistant' => [
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page' ] ],
]
]
// phpcs:enable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
];
/**
* The Construct method.
*
* @since 4.0.0
*
* @param string $optionsName An array of options.
*/
public function __construct( $optionsName = 'aioseo_options' ) {
$this->optionsName = $optionsName;
$this->init();
add_action( 'shutdown', [ $this, 'save' ] );
}
/**
* Initializes the options.
*
* @since 4.0.0
*
* @return void
*/
public function init() {
$this->setInitialDefaults();
add_action( 'init', [ $this, 'translateDefaults' ] );
$this->setDbOptions();
add_action( 'wp_loaded', [ $this, 'maybeFlushRewriteRules' ] );
}
/**
* Sets the DB options to the class after merging in new defaults and dropping unknown values.
*
* @since 4.0.14
*
* @return void
*/
public function setDbOptions() {
// Refactor options.
$this->defaultsMerged = array_replace_recursive( $this->defaults, $this->defaultsMerged );
$dbOptions = $this->getDbOptions( $this->optionsName );
$options = array_replace_recursive(
$this->defaultsMerged,
$this->addValueToValuesArray( $this->defaultsMerged, $dbOptions )
);
aioseo()->core->optionsCache->setOptions( $this->optionsName, apply_filters( 'aioseo_get_options', $options ) );
// Get the localized options.
$dbOptionsLocalized = get_option( $this->optionsName . '_localized' );
if ( empty( $dbOptionsLocalized ) ) {
$dbOptionsLocalized = [];
}
$this->localized = $dbOptionsLocalized;
}
/**
* Sets the initial defaults that can't be defined in the property because of PHP 5.4.
*
* @since 4.1.4
*
* @return void
*/
protected function setInitialDefaults() {
static $hasInitialized = false;
if ( $hasInitialized ) {
return;
}
$hasInitialized = true;
$this->defaults['searchAppearance']['global']['schema']['organizationLogo']['default'] = aioseo()->helpers->getSiteLogoUrl() ? aioseo()->helpers->getSiteLogoUrl() : '';
$this->defaults['advanced']['emailSummary']['recipients']['default'] = [
[
'email' => get_bloginfo( 'admin_email' ),
'frequency' => 'monthly',
]
];
}
/**
* For our defaults array, some options need to be translated, so we do that here.
*
* @since 4.0.0
*
* @return void
*/
public function translateDefaults() {
static $hasInitialized = false;
if ( $hasInitialized ) {
return;
}
$hasInitialized = true;
$default = sprintf( '{"label":"%1$s","value":"default"}', __( 'default', 'all-in-one-seo-pack' ) );
$this->defaults['sitemap']['general']['advancedSettings']['priority']['homePage']['priority']['default'] = $default;
$this->defaults['sitemap']['general']['advancedSettings']['priority']['homePage']['frequency']['default'] = $default;
$this->defaults['sitemap']['general']['advancedSettings']['priority']['postTypes']['priority']['default'] = $default;
$this->defaults['sitemap']['general']['advancedSettings']['priority']['postTypes']['frequency']['default'] = $default;
$this->defaults['sitemap']['general']['advancedSettings']['priority']['taxonomies']['priority']['default'] = $default;
$this->defaults['sitemap']['general']['advancedSettings']['priority']['taxonomies']['frequency']['default'] = $default;
$this->defaults['breadcrumbs']['homepageLabel']['default'] = __( 'Home', 'all-in-one-seo-pack' );
$this->defaults['breadcrumbs']['archiveFormat']['default'] = sprintf( '%1$s #breadcrumb_archive_post_type_name', __( 'Archives for', 'all-in-one-seo-pack' ) );
$this->defaults['breadcrumbs']['searchResultFormat']['default'] = sprintf( '%1$s \'#breadcrumb_search_string\'', __( 'Search Results for', 'all-in-one-seo-pack' ) );
$this->defaults['breadcrumbs']['errorFormat404']['default'] = __( '404 - Page Not Found', 'all-in-one-seo-pack' );
}
/**
* Sanitizes, then saves the options to the database.
*
* @since 4.0.0
*
* @param array $options An array of options to sanitize, then save.
* @return void
*/
public function sanitizeAndSave( $options ) {
$sitemapOptions = ! empty( $options['sitemap'] ) ? $options['sitemap'] : null;
$oldSitemapOptions = aioseo()->options->sitemap->all();
$generalSitemapOptions = ! empty( $options['sitemap']['general'] ) ? $options['sitemap']['general'] : null;
$oldGeneralSitemapOptions = aioseo()->options->sitemap->general->all();
$deprecatedGeneralSitemapOptions = ! empty( $options['deprecated']['sitemap']['general'] )
? $options['deprecated']['sitemap']['general']
: null;
$oldDeprecatedGeneralSitemapOptions = aioseo()->options->deprecated->sitemap->general->all();
$oldPhoneOption = aioseo()->options->searchAppearance->global->schema->phone;
$phoneNumberOptions = isset( $options['searchAppearance']['global']['schema']['phone'] )
? $options['searchAppearance']['global']['schema']['phone']
: null;
$oldHtmlSitemapUrl = aioseo()->options->sitemap->html->pageUrl;
$logsRetention = isset( $options['searchAppearance']['advanced']['blockArgs']['logsRetention'] ) ? $options['searchAppearance']['advanced']['blockArgs']['logsRetention'] : null;
$oldLogsRetention = aioseo()->options->searchAppearance->advanced->blockArgs->logsRetention;
// Remove category base.
$removeCategoryBase = isset( $options['searchAppearance']['advanced']['removeCategoryBase'] ) ? $options['searchAppearance']['advanced']['removeCategoryBase'] : null;
$removeCategoryBaseOld = aioseo()->options->searchAppearance->advanced->removeCategoryBase;
$options = $this->maybeRemoveUnfilteredHtmlFields( $options );
$this->init();
if ( ! is_array( $options ) ) {
return;
}
$this->sanitizeEmailSummary( $options );
// First, recursively replace the new options into the cached state.
// It's important we use the helper method since we want to replace populated arrays with empty ones if needed (when a setting was cleared out).
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$dbOptions = aioseo()->helpers->arrayReplaceRecursive(
$cachedOptions,
$this->addValueToValuesArray( $cachedOptions, $options, [], true )
);
// Now, we must also intersect both arrays to delete any individual keys that were unset.
// We must do this because, while arrayReplaceRecursive will update the values for keys or empty them out,
// it will keys that aren't present in the replacement array unaffected in the target array.
$dbOptions = aioseo()->helpers->arrayIntersectRecursive(
$dbOptions,
$this->addValueToValuesArray( $cachedOptions, $options, [], true ),
'value'
);
if ( isset( $options['social']['profiles']['additionalUrls'] ) ) {
$dbOptions['social']['profiles']['additionalUrls'] = preg_replace( '/\h/', "\n", (string) $options['social']['profiles']['additionalUrls'] );
}
$newOptions = ! empty( $options['sitemap']['html'] ) ? $options['sitemap']['html'] : null;
if ( ! empty( $newOptions ) && aioseo()->options->sitemap->html->enable ) {
$newOptions = ! empty( $options['sitemap']['html'] ) ? $options['sitemap']['html'] : null;
$pageUrl = wp_parse_url( $newOptions['pageUrl'] );
$path = ! empty( $pageUrl['path'] ) ? untrailingslashit( $pageUrl['path'] ) : '';
if ( $path ) {
$existingPage = get_page_by_path( $path, OBJECT );
if ( is_object( $existingPage ) ) {
// If the page exists, don't override the previous URL.
$options['sitemap']['html']['pageUrl'] = $oldHtmlSitemapUrl;
}
}
}
// Update the cache state.
aioseo()->core->optionsCache->setOptions( $this->optionsName, $dbOptions );
// Update localized options.
update_option( $this->optionsName . '_localized', $this->localized );
// Finally, save the new values to the DB.
$this->save( true );
// If phone settings have changed, let's see if we need to dump the phone number notice.
if (
$phoneNumberOptions &&
$phoneNumberOptions !== $oldPhoneOption
) {
$notification = Models\Notification::getNotificationByName( 'v3-migration-schema-number' );
if ( $notification->exists() ) {
Models\Notification::deleteNotificationByName( 'v3-migration-schema-number' );
}
}
// If sitemap settings were changed, static files need to be regenerated.
if (
! empty( $deprecatedGeneralSitemapOptions ) &&
! empty( $generalSitemapOptions )
) {
if (
(
aioseo()->helpers->arraysDifferent( $oldGeneralSitemapOptions, $generalSitemapOptions ) ||
aioseo()->helpers->arraysDifferent( $oldDeprecatedGeneralSitemapOptions, $deprecatedGeneralSitemapOptions )
) &&
$generalSitemapOptions['advancedSettings']['enable'] &&
! $deprecatedGeneralSitemapOptions['advancedSettings']['dynamic']
) {
aioseo()->sitemap->scheduleRegeneration();
}
}
// Add or remove schedule for clearing crawl cleanup logs.
if ( ! empty( $logsRetention ) && $oldLogsRetention !== $logsRetention ) {
aioseo()->crawlCleanup->scheduleClearingLogs();
}
if ( ! empty( $sitemapOptions ) ) {
aioseo()->searchStatistics->sitemap->maybeSync( $oldSitemapOptions, $sitemapOptions );
}
if (
null !== $removeCategoryBase &&
$removeCategoryBase !== $removeCategoryBaseOld
) {
aioseo()->options->flushRewriteRules();
}
// This is required in order for the Pro options to be refreshed before they save data again.
$this->refresh();
}
/**
* Sanitizes the `emailSummary` option.
*
* @since 4.7.2
*
* @param array $options All options, passed by reference.
* @return void
*/
private function sanitizeEmailSummary( &$options ) {
foreach ( ( $options['advanced']['emailSummary']['recipients'] ?? [] ) as $k => &$recipient ) {
$recipient['email'] = is_email( $recipient['email'] );
// Remove empty emails.
if ( empty( $recipient['email'] ) ) {
unset( $options['advanced']['emailSummary']['recipients'][ $k ] );
continue;
}
// Remove duplicate emails with the same frequency.
foreach ( $options['advanced']['emailSummary']['recipients'] as $k2 => $recipient2 ) {
if (
$k !== $k2 &&
$recipient['email'] === $recipient2['email'] &&
$recipient['frequency'] === $recipient2['frequency']
) {
unset( $options['advanced']['emailSummary']['recipients'][ $k ] );
break;
}
}
}
}
/**
* If the user does not have access to unfiltered HTML, we need to remove them from saving.
*
* @since 4.0.0
*
* @param array $options An array of options.
* @return array An array of options.
*/
private function maybeRemoveUnfilteredHtmlFields( $options ) {
if ( current_user_can( 'unfiltered_html' ) ) {
return $options;
}
if (
! empty( $options['webmasterTools'] ) &&
isset( $options['webmasterTools']['miscellaneousVerification'] )
) {
unset( $options['webmasterTools']['miscellaneousVerification'] );
}
if (
! empty( $options['rssContent'] ) &&
isset( $options['rssContent']['before'] )
) {
unset( $options['rssContent']['before'] );
}
if (
! empty( $options['rssContent'] ) &&
isset( $options['rssContent']['after'] )
) {
unset( $options['rssContent']['after'] );
}
return $options;
}
/**
* Indicate we need to flush rewrite rules on next load.
*
* @since 4.0.17
*
* @return void
*/
public function flushRewriteRules() {
update_option( 'aioseo_flush_rewrite_rules_flag', true );
}
/**
* Flush rewrite rules if needed.
*
* @since 4.0.17
*
* @return void
*/
public function maybeFlushRewriteRules() {
if ( get_option( 'aioseo_flush_rewrite_rules_flag' ) ) {
flush_rewrite_rules();
delete_option( 'aioseo_flush_rewrite_rules_flag' );
}
}
} home/xbodynamge/namtation/wp-content/plugins/all-in-one-seo-pack/app/Lite/Options/Options.php 0000644 00000002371 15114636451 0026322 0 ustar 00 <?php
namespace AIOSEO\Plugin\Lite\Options;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Options as CommonOptions;
use AIOSEO\Plugin\Lite\Traits;
/**
* Class that holds all options for AIOSEO.
*
* @since 4.0.0
*/
class Options extends CommonOptions\Options {
use Traits\Options;
/**
* Defaults options for Lite.
*
* @since 4.0.0
*
* @var array
*/
private $liteDefaults = [
// phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
'advanced' => [
'usageTracking' => [ 'type' => 'boolean', 'default' => false ]
]
// phpcs:enable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
];
/**
* Sanitizes, then saves the options to the database.
*
* @since 4.7.2
*
* @param array $options An array of options to sanitize, then save.
* @return void
*/
public function sanitizeAndSave( $options ) {
if ( isset( $options['advanced']['emailSummary']['recipients'] ) ) {
$options['advanced']['emailSummary']['recipients'] = [ array_shift( $options['advanced']['emailSummary']['recipients'] ) ];
$options['advanced']['emailSummary']['recipients'][0]['frequency'] = 'monthly';
}
parent::sanitizeAndSave( $options );
}
} home/xbodynamge/namtation/wp-content/plugins/all-in-one-seo-pack/app/Common/Traits/Options.php 0000644 00000067142 15114637017 0026476 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Traits;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Options trait.
*
* @since 4.0.0
*/
trait Options {
/**
* Whether or not this instance is a clone.
*
* @since 4.1.4
*
* @var boolean
*/
public $isClone = false;
/**
* Whether or not the options need to be saved to the DB.
*
* @since 4.1.4
*
* @var string
*/
public $shouldSave = false;
/**
* The name to lookup the options with.
*
* @since 4.0.0
*
* @var string
*/
public $optionsName = '';
/**
* Holds the localized options.
*
* @since 4.0.0
*
* @var array
*/
public $localized = [];
/**
* The group key we are working with.
*
* @since 4.0.0
*
* @var string|null
*/
protected $groupKey = null;
/**
* Allows us to create unlimited number of sub groups.
* Like so: options->breadcrumbs->templates->taxonomies->tags->template
*
* @since 4.0.0
*
* @var array
*/
protected $subGroups = [];
/**
* Any arguments associated with a dynamic method.
*
* @since 4.0.0
*
* @var array
*/
protected $arguments = [];
/**
* The value to set on an option.
*
* @since 4.0.0
*
* @var mixed
*/
protected $value = null;
/**
* Holds all the defaults after they have been merged.
*
* @since 4.0.0
*
* @var array
*/
protected $defaultsMerged = [];
/**
* Holds a redirect link or slug.
*
* @since 4.0.17
*
* @var string
*/
protected $screenRedirection = '';
/**
* Retrieve an option or null if missing.
*
* @since 4.0.0
*
* @param string $name The name of the property that is missing on the class.
* @param array $arguments The arguments passed into the method.
* @return mixed The value from the options or default/null.
*/
public function __call( $name, $arguments = [] ) {
if ( $this->setGroupKey( $name, $arguments ) ) {
return $this;
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = $cachedOptions[ $this->groupKey ];
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = $defaults[ $subGroup ];
}
}
if ( ! isset( $defaults[ $name ] ) ) {
$this->resetGroups();
return ! empty( $this->arguments[0] )
? $this->arguments[0]
: $this->getDefault( $name, false );
}
if ( empty( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
$value = isset( $cachedOptions[ $this->groupKey ][ $name ]['value'] )
? $cachedOptions[ $this->groupKey ][ $name ]['value']
: (
! empty( $this->arguments[0] )
? $this->arguments[0]
: $this->getDefault( $name, false )
);
$this->resetGroups();
return $value;
}
/**
* Retrieve an option or null if missing.
*
* @since 4.0.0
*
* @param string $name The name of the property that is missing on the class.
* @return mixed The value from the options or default/null.
*/
public function __get( $name ) {
if ( 'type' === $name ) {
$name = '_aioseo_type';
}
if ( $this->setGroupKey( $name ) ) {
return $this;
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = $cachedOptions[ $this->groupKey ];
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = $defaults[ $subGroup ];
}
}
if ( ! isset( $defaults[ $name ] ) ) {
$default = $this->getDefault( $name, false );
$this->resetGroups();
return $default;
}
if ( ! isset( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
$value = $this->getDefault( $name, false );
if ( isset( $defaults[ $name ]['value'] ) ) {
$preserveHtml = ! empty( $defaults[ $name ]['preserveHtml'] );
if ( $preserveHtml ) {
if ( is_array( $defaults[ $name ]['value'] ) ) {
foreach ( $defaults[ $name ]['value'] as $k => $v ) {
$defaults[ $name ]['value'][ $k ] = html_entity_decode( $v, ENT_NOQUOTES );
}
} else {
$defaults[ $name ]['value'] = html_entity_decode( $defaults[ $name ]['value'], ENT_NOQUOTES );
}
}
$value = $defaults[ $name ]['value'];
// Localized value.
if ( isset( $defaults[ $name ]['localized'] ) ) {
$localizedKey = $this->groupKey;
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$localizedKey .= '_' . $subGroup;
}
}
$localizedKey .= '_' . $name;
if ( ! empty( $this->localized[ $localizedKey ] ) ) {
$value = $this->localized[ $localizedKey ];
// We need to rebuild the keywords as a json string.
if ( 'keywords' === $name ) {
$keywords = explode( ',', $value );
foreach ( $keywords as $k => $keyword ) {
$keywords[ $k ] = [
'label' => $keyword,
'value' => $keyword
];
}
$value = wp_json_encode( $keywords );
}
}
}
}
$this->resetGroups();
return $value;
}
/**
* Sets the option value and saves to the database.
*
* @since 4.0.0
*
* @param string $name The name of the option.
* @param mixed $value The value to set.
* @return void
*/
public function __set( $name, $value ) {
if ( $this->setGroupKey( $name, null, $value ) ) {
return $this;
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = json_decode( wp_json_encode( $cachedOptions[ $this->groupKey ] ), true );
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = &$defaults[ $subGroup ];
}
}
if ( ! isset( $defaults[ $name ] ) ) {
$default = $this->getDefault( $name, false );
$this->resetGroups();
return $default;
}
if ( empty( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
$preserveHtml = ! empty( $defaults[ $name ]['preserveHtml'] );
$localized = ! empty( $defaults[ $name ]['localized'] );
$defaults[ $name ]['value'] = $this->sanitizeField( $this->value, $defaults[ $name ]['type'], $preserveHtml );
if ( $localized ) {
$localizedKey = $this->groupKey;
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$localizedKey .= '_' . $subGroup;
}
}
$localizedKey .= '_' . $name;
$localizedValue = $defaults[ $name ]['value'];
if ( 'keywords' === $name ) {
$keywords = json_decode( $localizedValue ) ? json_decode( $localizedValue ) : [];
foreach ( $keywords as $k => $keyword ) {
$keywords[ $k ] = $keyword->value;
}
$localizedValue = implode( ',', $keywords );
}
$this->localized[ $localizedKey ] = $localizedValue;
update_option( $this->optionsName . '_localized', $this->localized );
}
$originalDefaults = json_decode( wp_json_encode( $cachedOptions[ $this->groupKey ] ), true );
$pointer = &$originalDefaults; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
foreach ( $this->subGroups as $subGroup ) {
$pointer = &$pointer[ $subGroup ];
}
$pointer = $defaults;
$cachedOptions[ $this->groupKey ] = $originalDefaults;
aioseo()->core->optionsCache->setOptions( $this->optionsName, $cachedOptions );
$this->resetGroups();
$this->update();
}
/**
* Checks if an option is set or returns null if not.
*
* @since 4.0.0
*
* @param string $name The name of the option.
* @return mixed True or null.
*/
public function __isset( $name ) {
if ( $this->setGroupKey( $name ) ) {
return $this;
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = $cachedOptions[ $this->groupKey ];
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = &$defaults[ $subGroup ];
}
}
if ( ! isset( $defaults[ $name ] ) ) {
$this->resetGroups();
return false;
}
if ( empty( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
$value = isset( $defaults[ $name ]['value'] )
? false === empty( $defaults[ $name ]['value'] )
: false;
$this->resetGroups();
return $value;
}
/**
* Unsets the option value and saves to the database.
*
* @since 4.0.0
*
* @param string $name The name of the option.
* @return void
*/
public function __unset( $name ) {
if ( $this->setGroupKey( $name ) ) {
return $this;
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = json_decode( wp_json_encode( $cachedOptions[ $this->groupKey ] ), true );
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = &$defaults[ $subGroup ];
}
}
if ( ! isset( $defaults[ $name ] ) ) {
$this->groupKey = null;
$this->subGroups = [];
return;
}
if ( empty( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
if ( ! isset( $defaults[ $name ]['value'] ) ) {
return;
}
unset( $defaults[ $name ]['value'] );
$cachedOptions[ $this->groupKey ] = $defaults;
aioseo()->core->optionsCache->setOptions( $this->optionsName, $cachedOptions );
$this->resetGroups();
$this->update();
}
/**
* Retrieves all options.
*
* @since 4.0.0
*
* @param array $include Keys to include.
* @param array $exclude Keys to exclude.
* @return array An array of options.
*/
public function all( $include = [], $exclude = [] ) {
$originalGroupKey = $this->groupKey;
$originalSubGroups = $this->subGroups;
// Make sure our dynamic options have loaded.
$this->init();
// Refactor options.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$refactored = $this->convertOptionsToValues( $cachedOptions );
$this->groupKey = null;
if ( ! $originalGroupKey ) {
return $this->allFiltered( $refactored, $include, $exclude );
}
if ( empty( $originalSubGroups ) ) {
$all = $refactored[ $originalGroupKey ];
return $this->allFiltered( $all, $include, $exclude );
}
$returnable = &$refactored[ $originalGroupKey ]; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
foreach ( $originalSubGroups as $subGroup ) {
$returnable = &$returnable[ $subGroup ];
}
$this->resetGroups();
return $this->allFiltered( $returnable, $include, $exclude );
}
/**
* Reset the current option to the defaults.
*
* @since 4.0.0
*
* @param array $include Keys to include.
* @param array $exclude Keys to exclude.
* @return void
*/
public function reset( $include = [], $exclude = [] ) {
$originalGroupKey = $this->groupKey;
$originalSubGroups = $this->subGroups;
// Make sure our dynamic options have loaded.
$this->init();
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
// If we don't have a group key set, it means we want to reset everything.
if ( empty( $originalGroupKey ) ) {
$groupKeys = array_keys( $cachedOptions );
foreach ( $groupKeys as $groupKey ) {
$this->groupKey = $groupKey;
$this->reset();
}
// Since we just finished resetting everything, we can return early.
return;
}
// If we need to set a sub-group, do that now.
$keys = array_merge( [ $originalGroupKey ], $originalSubGroups );
$defaults = json_decode( wp_json_encode( $cachedOptions[ $originalGroupKey ] ), true );
if ( ! empty( $originalSubGroups ) ) {
foreach ( $originalSubGroups as $subGroup ) {
$defaults = $defaults[ $subGroup ];
}
}
// Refactor options.
$resetValues = $this->resetValues( $defaults, $this->defaultsMerged, $keys, $include, $exclude );
// We need to call our helper method instead of the built-in array_replace_recursive() function here because we want values to be replaced with empty arrays.
$defaults = aioseo()->helpers->arrayReplaceRecursive( $defaults, $resetValues );
$originalDefaults = json_decode( wp_json_encode( $cachedOptions[ $originalGroupKey ] ), true );
$pointer = &$originalDefaults; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
foreach ( $originalSubGroups as $subGroup ) {
$pointer = &$pointer[ $subGroup ];
}
$pointer = $defaults;
$cachedOptions[ $originalGroupKey ] = $originalDefaults;
aioseo()->core->optionsCache->setOptions( $this->optionsName, $cachedOptions );
$this->resetGroups();
$this->update();
}
/**
* Resets all values in a group.
*
* @since 4.0.0
*
* @param array $defaults The defaults array we are currently working with.
* @param array $values The values to adjust.
* @param array $keys Parent keys for the current group we are parsing.
* @param array $include Keys to include.
* @param array $exclude Keys to exclude.
* @return array The modified values.
*/
protected function resetValues( $values, $defaults, $keys = [], $include = [], $exclude = [] ) {
$values = $this->allFiltered( $values, $include, $exclude );
foreach ( $values as $key => $value ) {
$option = $this->isAnOption( $key, $defaults, $keys );
if ( $option ) {
$values[ $key ]['value'] = isset( $values[ $key ]['default'] ) ? $values[ $key ]['default'] : null;
continue;
}
$keys[] = $key;
$values[ $key ] = $this->resetValues( $value, $defaults, $keys );
array_pop( $keys );
}
return $values;
}
/**
* Checks if the current group has an option or group.
*
* @since 4.0.0
*
* @param string $optionOrGroup The option or group to look for.
* @param bool $resetGroups Whether or not to reset the groups after.
* @return bool True if it does, false if not.
*/
public function has( $optionOrGroup = '', $resetGroups = true ) {
if ( 'type' === $optionOrGroup ) {
$optionOrGroup = '_aioseo_type';
}
$originalGroupKey = $this->groupKey;
$originalSubGroups = $this->subGroups;
static $hasInitialized = false;
if ( ! $hasInitialized ) {
$hasInitialized = true;
$this->init();
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = $originalGroupKey ? $cachedOptions[ $originalGroupKey ] : $cachedOptions;
if ( ! empty( $originalSubGroups ) ) {
foreach ( $originalSubGroups as $subGroup ) {
$defaults = $defaults[ $subGroup ];
}
}
if ( $resetGroups ) {
$this->resetGroups();
}
if ( ! empty( $defaults[ $optionOrGroup ] ) ) {
return true;
}
return false;
}
/**
* Filters the results based on passed in array.
*
* @since 4.0.0
*
* @param array $all All the options to filter.
* @param array $include Keys to include.
* @param array $exclude Keys to exclude.
* @return array The filtered options.
*/
private function allFiltered( $all, $include, $exclude ) {
if ( ! empty( $include ) ) {
return array_intersect_ukey( $all, $include, function ( $key1, $key2 ) use ( $include ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
if ( in_array( $key1, $include, true ) ) {
return 0;
}
return -1;
} );
}
if ( ! empty( $exclude ) ) {
return array_diff_ukey( $all, $exclude, function ( $key1, $key2 ) use ( $exclude ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
if ( ! in_array( $key1, $exclude, true ) ) {
return 0;
}
return -1;
} );
}
return $all;
}
/**
* Gets the default value for an option.
*
* @since 4.0.0
*
* @param string $name The option name.
* @return mixed The default value.
*/
public function getDefault( $name, $resetGroups = true ) {
$defaults = $this->defaultsMerged[ $this->groupKey ];
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
if ( empty( $defaults[ $subGroup ] ) ) {
return null;
}
$defaults = $defaults[ $subGroup ];
}
}
if ( $resetGroups ) {
$this->resetGroups();
}
if ( ! isset( $defaults[ $name ] ) ) {
return null;
}
if ( empty( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
return isset( $defaults[ $name ]['default'] )
? $defaults[ $name ]['default']
: null;
}
/**
* Gets the defaults options.
*
* @since 4.1.3
*
* @return array An array of dafults.
*/
public function getDefaults() {
return $this->defaults;
}
/**
* Updates the options in the database.
*
* @since 4.0.0
*
* @param string $optionsName An optional option name to update.
* @param string $defaults The defaults to filter the options by.
* @param array|null $options An optional options array.
* @return void
*/
public function update( $optionsName = null, $defaults = null, $options = null ) {
$optionsName = empty( $optionsName ) ? $this->optionsName : $optionsName;
$defaults = empty( $defaults ) ? $this->defaults : $defaults;
// First, we need to filter our options.
$options = $this->filterOptions( $defaults, $options );
// Refactor options.
$refactored = $this->convertOptionsToValues( $options );
$this->resetGroups();
// The following needs to happen here (possibly a clone) as well as in the main instance.
$originalInstance = $this->getOriginalInstance();
// Update the DB options.
aioseo()->core->optionsCache->setDb( $optionsName, $refactored );
// Force a save here and in the main class.
$this->shouldSave = true;
$originalInstance->shouldSave = true;
}
/**
* Updates the options in the database.
*
* @since 4.1.4
*
* @param boolean $force Whether or not to force an immediate save.
* @param string $optionsName An optional option name to update.
* @param string $defaults The defaults to filter the options by.
* @return void
*/
public function save( $force = false, $optionsName = null, $defaults = null ) {
if ( ! $this->shouldSave && ! $force ) {
return;
}
$optionsName = empty( $optionsName ) ? $this->optionsName : $optionsName;
$defaults = empty( $defaults ) ? $this->defaults : $defaults;
$this->update( $optionsName );
// First, we need to filter our options.
$options = $this->filterOptions( $defaults );
// Refactor options.
$refactored = $this->convertOptionsToValues( $options );
$this->resetGroups();
update_option( $optionsName, wp_json_encode( $refactored ) );
}
/**
* Filter options to match our defaults.
*
* @since 4.0.0
*
* @param array $defaults The defaults to use in filtering.
* @param array|null $options An optional options array.
* @return array An array of filtered options.
*/
public function filterOptions( $defaults, $options = null ) {
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$options = ! empty( $options ) ? $options : json_decode( wp_json_encode( $cachedOptions ), true );
return $this->filterRecursively( $options, $defaults );
}
/**
* Filters options in a loop.
*
* @since 4.0.0
*
* @param array $options An array of options to filter.
* @param array $defaults An array of defaults to filter against.
* @return array A filtered array of options.
*/
public function filterRecursively( $options, $defaults ) {
if ( ! is_array( $options ) ) {
return $options;
}
foreach ( $options as $key => $value ) {
if ( ! isset( $defaults[ $key ] ) ) {
unset( $options[ $key ] );
continue;
}
if ( ! isset( $value['type'] ) ) {
$options[ $key ] = $this->filterRecursively( $options[ $key ], $defaults[ $key ] );
continue;
}
}
return $options;
}
/**
* Sanitizes the value before allowing it to be saved.
*
* @since 4.0.0
*
* @param mixed $value The value to sanitize.
* @param string $type The type of sanitization to do.
* @return mixed The sanitized value.
*/
public function sanitizeField( $value, $type, $preserveHtml = false ) {
switch ( $type ) {
case 'boolean':
return (bool) $value;
case 'html':
return sanitize_textarea_field( $value );
case 'string':
return sanitize_text_field( $value );
case 'number':
return intval( $value );
case 'array':
$array = [];
foreach ( (array) $value as $k => $v ) {
if ( is_array( $v ) ) {
$array[ $k ] = $this->sanitizeField( $v, 'array' );
continue;
}
$array[ $k ] = sanitize_text_field( $preserveHtml ? htmlspecialchars( $v, ENT_NOQUOTES, 'UTF-8' ) : $v );
}
return $array;
case 'float':
return floatval( $value );
}
}
/**
* Checks to see if we need to set the group key. If so, will return true.
*
* @since 4.0.0
*
* @param string $name The name of the option to set.
* @param array $arguments Any arguments needed if this was a method called.
* @param mixed $value The value if we are setting an option.
* @return boolean Whether or not we need to set the group key.
*/
private function setGroupKey( $name, $arguments = null, $value = null ) {
$this->arguments = $arguments;
$this->value = $value;
if ( empty( $this->groupKey ) ) {
$groups = array_keys( $this->defaultsMerged );
if ( in_array( $name, $groups, true ) ) {
$this->groupKey = $name;
return true;
}
$this->groupKey = $groups[0];
}
return false;
}
/**
* Sets the sub group key. Will set and return the instance.
*
* @since 4.0.0
*
* @param string $name The name of the option to set.
* @param array $arguments Any arguments needed if this was a method called.
* @param mixed $value The value if we are setting an option.
* @return object The options object.
*/
private function setSubGroup( $name, $arguments = null, $value = null ) {
if ( ! is_null( $arguments ) ) {
$this->arguments = $arguments;
}
if ( ! is_null( $value ) ) {
$this->value = $value;
}
$defaults = $this->defaultsMerged[ $this->groupKey ];
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = $defaults[ $subGroup ];
}
}
$groups = array_keys( $defaults );
if ( in_array( $name, $groups, true ) ) {
$this->subGroups[] = $name;
}
return $this;
}
/**
* Reset groups.
*
* @since 4.0.0
*
* @return void
*/
protected function resetGroups() {
$this->groupKey = null;
$this->subGroups = [];
}
/**
* Converts an associative array of values into a structure
* that works with our defaults.
*
* @since 4.0.0
*
* @param array $defaults The defaults array we are currently working with.
* @param array $values The values to adjust.
* @param array $keys Parent keys for the current group we are parsing.
* @param bool $sanitize Whether or not we should sanitize the value.
* @return array The modified values.
*/
protected function addValueToValuesArray( $defaults, $values, $keys = [], $sanitize = false ) {
foreach ( $values as $key => $value ) {
$option = $this->isAnOption( $key, $defaults, $keys );
if ( $option ) {
$preserveHtml = ! empty( $option['preserveHtml'] );
$newValue = $sanitize ? $this->sanitizeField( $value, $option['type'], $preserveHtml ) : $value;
$values[ $key ] = [
'value' => $newValue
];
// If this is a localized string, let's save it to our localized options.
if ( $sanitize && ! empty( $option['localized'] ) ) {
$localizedKey = '';
foreach ( $keys as $k ) {
$localizedKey .= $k . '_';
}
$localizedKey .= $key;
$localizedValue = $newValue;
if ( 'keywords' === $key ) {
$keywords = json_decode( $localizedValue ) ? json_decode( $localizedValue ) : [];
foreach ( $keywords as $k => $keyword ) {
$keywords[ $k ] = $keyword->value;
}
$localizedValue = implode( ',', $keywords );
}
$this->localized[ $localizedKey ] = $localizedValue;
}
continue;
}
if ( ! is_array( $value ) ) {
continue;
}
$keys[] = $key;
$values[ $key ] = $this->addValueToValuesArray( $defaults, $value, $keys, $sanitize );
array_pop( $keys );
}
return $values;
}
/**
* Our options array has values (or defaults).
* This method converts them to how we would store them
* in the DB.
*
* @since 4.0.0
*
* @param array $options The options array.
* @return array The converted options array.
*/
public function convertOptionsToValues( $options, $optionKey = 'type' ) {
foreach ( $options as $key => $value ) {
if ( ! is_array( $value ) ) {
continue;
}
if ( ! isset( $value[ $optionKey ] ) ) {
$options[ $key ] = $this->convertOptionsToValues( $value, $optionKey );
continue;
}
$options[ $key ] = null;
if ( isset( $value['value'] ) ) {
$preserveHtml = ! empty( $value['preserveHtml'] );
if ( $preserveHtml ) {
if ( is_array( $value['value'] ) ) {
foreach ( $value['value'] as $k => $v ) {
$value['value'][ $k ] = html_entity_decode( $v, ENT_NOQUOTES );
}
} else {
$value['value'] = html_entity_decode( $value['value'], ENT_NOQUOTES );
}
}
$options[ $key ] = $value['value'];
continue;
}
if ( isset( $value['default'] ) ) {
$options[ $key ] = $value['default'];
}
}
return $options;
}
/**
* This checks to see if the current array/option is really an option
* and not just another parent with a subgroup.
*
* @since 4.0.0
*
* @param string $key The current array key we are working with.
* @param array $defaults The defaults array to check against.
* @param array $keys The parent keys to loop through.
* @return bool Whether or not this is an option.
*/
private function isAnOption( $key, $defaults, $keys ) {
if ( ! empty( $keys ) ) {
foreach ( $keys as $k ) {
$defaults = isset( $defaults[ $k ] ) ? $defaults[ $k ] : [];
}
}
if ( isset( $defaults[ $key ]['type'] ) ) {
return $defaults[ $key ];
}
return false;
}
/**
* Refreshes the options from the database.
*
* We need this during the migration to update through clones.
*
* @since 4.0.0
*
* @return void
*/
public function refresh() {
// Reset DB options to clear the cache.
aioseo()->core->optionsCache->resetDb();
$this->init();
}
/**
* Returns the DB options.
*
* @since 4.1.4
*
* @param string $optionsName The options name.
* @return array The options.
*/
public function getDbOptions( $optionsName ) {
$cache = aioseo()->core->optionsCache->getDb( $optionsName );
if ( empty( $cache ) ) {
$options = json_decode( get_option( $optionsName ), true );
$options = ! empty( $options ) ? $options : [];
// Set the cache.
aioseo()->core->optionsCache->setDb( $optionsName, $options );
}
return aioseo()->core->optionsCache->getDb( $optionsName );
}
/**
* In order to not have a conflict, we need to return a clone.
*
* @since 4.0.0
*
* @param bool $reInitialize Whether to reinitialize on the clone.
* @return object The cloned Options object.
*/
public function noConflict( $reInitialize = false ) {
$class = clone $this;
$class->isClone = true;
if ( $reInitialize ) {
$class->init();
}
return $class;
}
/**
* Get original instance. Since this could be a cloned object, let's get the original instance.
*
* @since 4.1.4
*
* @return self
*/
public function getOriginalInstance() {
if ( ! $this->isClone ) {
return $this;
}
$class = new \ReflectionClass( get_called_class() );
$optionName = aioseo()->helpers->toCamelCase( $class->getShortName() );
if ( isset( aioseo()->{ $optionName } ) ) {
return aioseo()->{ $optionName };
}
return $this;
}
} home/xbodynamge/dev/wp-content/plugins/all-in-one-seo-pack/app/Common/Options/Options.php 0000644 00000106145 15114645315 0025444 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Options;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
use AIOSEO\Plugin\Common\Traits;
/**
* Class that holds all options for AIOSEO.
*
* @since 4.0.0
*/
class Options {
use Traits\Options;
/**
* All the default options.
*
* @since 4.0.0
*
* @var array
*/
protected $defaults = [
// phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
'internal' => [],
'webmasterTools' => [
'google' => [ 'type' => 'string' ],
'bing' => [ 'type' => 'string' ],
'yandex' => [ 'type' => 'string' ],
'baidu' => [ 'type' => 'string' ],
'pinterest' => [ 'type' => 'string' ],
'microsoftClarityProjectId' => [ 'type' => 'string' ],
'norton' => [ 'type' => 'string' ],
'miscellaneousVerification' => [ 'type' => 'html' ]
],
'breadcrumbs' => [
'separator' => [ 'type' => 'string', 'default' => '»' ],
'homepageLink' => [ 'type' => 'boolean', 'default' => true ],
'homepageLabel' => [ 'type' => 'string', 'default' => 'Home' ],
'breadcrumbPrefix' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'archiveFormat' => [ 'type' => 'string', 'default' => 'Archives for #breadcrumb_archive_post_type_name', 'localized' => true ],
'searchResultFormat' => [ 'type' => 'string', 'default' => 'Search Results for \'#breadcrumb_search_string\'', 'localized' => true ],
'errorFormat404' => [ 'type' => 'string', 'default' => '404 - Page Not Found', 'localized' => true ],
'showCurrentItem' => [ 'type' => 'boolean', 'default' => true ],
'linkCurrentItem' => [ 'type' => 'boolean', 'default' => false ],
'categoryFullHierarchy' => [ 'type' => 'boolean', 'default' => false ],
'showBlogHome' => [ 'type' => 'boolean', 'default' => false ]
],
'rssContent' => [
'before' => [ 'type' => 'html' ],
'after' => [
'type' => 'html',
'default' => <<<TEMPLATE
<p>The post #post_link first appeared on #site_link.</p>
TEMPLATE
]
],
'advanced' => [
'truSeo' => [ 'type' => 'boolean', 'default' => true ],
'headlineAnalyzer' => [ 'type' => 'boolean', 'default' => true ],
'seoAnalysis' => [ 'type' => 'boolean', 'default' => true ],
'dashboardWidgets' => [ 'type' => 'array', 'default' => [ 'seoSetup', 'seoOverview', 'seoNews' ] ],
'announcements' => [ 'type' => 'boolean', 'default' => true ],
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page', 'product' ] ],
],
'taxonomies' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'category', 'post_tag', 'product_cat', 'product_tag' ] ],
],
'uninstall' => [ 'type' => 'boolean', 'default' => false ],
'emailSummary' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'recipients' => [ 'type' => 'array', 'default' => [] ]
]
],
'sitemap' => [
'general' => [
'enable' => [ 'type' => 'boolean', 'default' => true ],
'filename' => [ 'type' => 'string', 'default' => 'sitemap' ],
'indexes' => [ 'type' => 'boolean', 'default' => true ],
'linksPerIndex' => [ 'type' => 'number', 'default' => 1000 ],
// @TODO: [V4+] Convert this to the dynamic options like in search appearance so we can have backups when plugins are deactivated.
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page', 'attachment', 'product' ] ],
],
// @TODO: [V4+] Convert this to the dynamic options like in search appearance so we can have backups when plugins are deactivated.
'taxonomies' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'category', 'post_tag', 'product_cat', 'product_tag' ] ],
],
'author' => [ 'type' => 'boolean', 'default' => false ],
'date' => [ 'type' => 'boolean', 'default' => false ],
'additionalPages' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'pages' => [ 'type' => 'array', 'default' => [] ]
],
'advancedSettings' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'excludeImages' => [ 'type' => 'boolean', 'default' => false ],
'excludePosts' => [ 'type' => 'array', 'default' => [] ],
'excludeTerms' => [ 'type' => 'array', 'default' => [] ],
'priority' => [
'homePage' => [
'priority' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ],
'frequency' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ]
],
'postTypes' => [
'grouped' => [ 'type' => 'boolean', 'default' => true ],
'priority' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ],
'frequency' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ]
],
'taxonomies' => [
'grouped' => [ 'type' => 'boolean', 'default' => true ],
'priority' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ],
'frequency' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ]
],
'archive' => [
'priority' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ],
'frequency' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ]
],
'author' => [
'priority' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ],
'frequency' => [ 'type' => 'string', 'default' => '{"label":"default","value":"default"}' ]
]
]
]
],
'rss' => [
'enable' => [ 'type' => 'boolean', 'default' => true ],
'linksPerIndex' => [ 'type' => 'number', 'default' => 50 ],
// @TODO: [V4+] Convert this to the dynamic options like in search appearance so we can have backups when plugins are deactivated.
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page', 'product' ] ],
]
],
'html' => [
'enable' => [ 'type' => 'boolean', 'default' => true ],
'pageUrl' => [ 'type' => 'string', 'default' => '' ],
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page', 'product' ] ],
],
'taxonomies' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'category', 'post_tag', 'product_cat', 'product_tag' ] ],
],
'sortOrder' => [ 'type' => 'string', 'default' => 'publish_date' ],
'sortDirection' => [ 'type' => 'string', 'default' => 'asc' ],
'publicationDate' => [ 'type' => 'boolean', 'default' => true ],
'compactArchives' => [ 'type' => 'boolean', 'default' => false ],
'advancedSettings' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'nofollowLinks' => [ 'type' => 'boolean', 'default' => false ],
'excludePosts' => [ 'type' => 'array', 'default' => [] ],
'excludeTerms' => [ 'type' => 'array', 'default' => [] ]
]
],
],
'social' => [
'profiles' => [
'sameUsername' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'username' => [ 'type' => 'string' ],
'included' => [ 'type' => 'array', 'default' => [ 'facebookPageUrl', 'twitterUrl', 'tiktokUrl', 'pinterestUrl', 'instagramUrl', 'youtubeUrl', 'linkedinUrl' ] ]
],
'urls' => [
'facebookPageUrl' => [ 'type' => 'string' ],
'twitterUrl' => [ 'type' => 'string' ],
'instagramUrl' => [ 'type' => 'string' ],
'tiktokUrl' => [ 'type' => 'string' ],
'pinterestUrl' => [ 'type' => 'string' ],
'youtubeUrl' => [ 'type' => 'string' ],
'linkedinUrl' => [ 'type' => 'string' ],
'tumblrUrl' => [ 'type' => 'string' ],
'yelpPageUrl' => [ 'type' => 'string' ],
'soundCloudUrl' => [ 'type' => 'string' ],
'wikipediaUrl' => [ 'type' => 'string' ],
'myspaceUrl' => [ 'type' => 'string' ],
'googlePlacesUrl' => [ 'type' => 'string' ],
'wordPressUrl' => [ 'type' => 'string' ],
'blueskyUrl' => [ 'type' => 'string' ],
'threadsUrl' => [ 'type' => 'string' ]
],
'additionalUrls' => [ 'type' => 'string' ]
],
'facebook' => [
'general' => [
'enable' => [ 'type' => 'boolean', 'default' => true ],
'defaultImageSourcePosts' => [ 'type' => 'string', 'default' => 'default' ],
'customFieldImagePosts' => [ 'type' => 'string' ],
'defaultImagePosts' => [ 'type' => 'string', 'default' => '' ],
'defaultImagePostsWidth' => [ 'type' => 'number', 'default' => '' ],
'defaultImagePostsHeight' => [ 'type' => 'number', 'default' => '' ],
'showAuthor' => [ 'type' => 'boolean', 'default' => true ],
'siteName' => [ 'type' => 'string', 'localized' => true, 'default' => '#site_title #separator_sa #tagline' ]
],
'homePage' => [
'image' => [ 'type' => 'string', 'default' => '' ],
'title' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'description' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'imageWidth' => [ 'type' => 'number', 'default' => '' ],
'imageHeight' => [ 'type' => 'number', 'default' => '' ],
'objectType' => [ 'type' => 'string', 'default' => 'website' ]
],
'advanced' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'adminId' => [ 'type' => 'string', 'default' => '' ],
'appId' => [ 'type' => 'string', 'default' => '' ],
'authorUrl' => [ 'type' => 'string', 'default' => '' ],
'generateArticleTags' => [ 'type' => 'boolean', 'default' => false ],
'useKeywordsInTags' => [ 'type' => 'boolean', 'default' => true ],
'useCategoriesInTags' => [ 'type' => 'boolean', 'default' => true ],
'usePostTagsInTags' => [ 'type' => 'boolean', 'default' => true ]
]
],
'twitter' => [
'general' => [
'enable' => [ 'type' => 'boolean', 'default' => true ],
'useOgData' => [ 'type' => 'boolean', 'default' => true ],
'defaultCardType' => [ 'type' => 'string', 'default' => 'summary_large_image' ],
'defaultImageSourcePosts' => [ 'type' => 'string', 'default' => 'default' ],
'customFieldImagePosts' => [ 'type' => 'string' ],
'defaultImagePosts' => [ 'type' => 'string', 'default' => '' ],
'showAuthor' => [ 'type' => 'boolean', 'default' => true ],
'additionalData' => [ 'type' => 'boolean', 'default' => false ]
],
'homePage' => [
'image' => [ 'type' => 'string', 'default' => '' ],
'title' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'description' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'cardType' => [ 'type' => 'string', 'default' => 'summary' ]
],
]
],
'searchAppearance' => [
'global' => [
'separator' => [ 'type' => 'string', 'default' => '-' ],
'siteTitle' => [ 'type' => 'string', 'localized' => true, 'default' => '#site_title #separator_sa #tagline' ],
'metaDescription' => [ 'type' => 'string', 'localized' => true, 'default' => '#tagline' ],
'keywords' => [ 'type' => 'string', 'localized' => true ],
'schema' => [
'websiteName' => [ 'type' => 'string', 'default' => '#site_title' ],
'websiteAlternateName' => [ 'type' => 'string' ],
'siteRepresents' => [ 'type' => 'string', 'default' => 'organization' ],
'person' => [ 'type' => 'string' ],
'organizationName' => [ 'type' => 'string', 'default' => '#site_title' ],
'organizationDescription' => [ 'type' => 'string', 'default' => '#tagline' ],
'organizationLogo' => [ 'type' => 'string' ],
'personName' => [ 'type' => 'string' ],
'personLogo' => [ 'type' => 'string' ],
'phone' => [ 'type' => 'string' ],
'email' => [ 'type' => 'string' ],
'foundingDate' => [ 'type' => 'string' ],
'numberOfEmployees' => [
'isRange' => [ 'type' => 'boolean' ],
'from' => [ 'type' => 'number' ],
'to' => [ 'type' => 'number' ],
'number' => [ 'type' => 'number' ]
]
]
],
'advanced' => [
'globalRobotsMeta' => [
'default' => [ 'type' => 'boolean', 'default' => true ],
'noindex' => [ 'type' => 'boolean', 'default' => false ],
'nofollow' => [ 'type' => 'boolean', 'default' => false ],
'noindexPaginated' => [ 'type' => 'boolean', 'default' => true ],
'nofollowPaginated' => [ 'type' => 'boolean', 'default' => true ],
'noindexFeed' => [ 'type' => 'boolean', 'default' => true ],
'noarchive' => [ 'type' => 'boolean', 'default' => false ],
'noimageindex' => [ 'type' => 'boolean', 'default' => false ],
'notranslate' => [ 'type' => 'boolean', 'default' => false ],
'nosnippet' => [ 'type' => 'boolean', 'default' => false ],
'noodp' => [ 'type' => 'boolean', 'default' => false ],
'maxSnippet' => [ 'type' => 'number', 'default' => -1 ],
'maxVideoPreview' => [ 'type' => 'number', 'default' => -1 ],
'maxImagePreview' => [ 'type' => 'string', 'default' => 'large' ]
],
'noIndexEmptyCat' => [ 'type' => 'boolean', 'default' => true ],
'removeStopWords' => [ 'type' => 'boolean', 'default' => false ],
'useKeywords' => [ 'type' => 'boolean', 'default' => false ],
'keywordsLooking' => [ 'type' => 'boolean', 'default' => true ],
'useCategoriesForMetaKeywords' => [ 'type' => 'boolean', 'default' => false ],
'useTagsForMetaKeywords' => [ 'type' => 'boolean', 'default' => false ],
'dynamicallyGenerateKeywords' => [ 'type' => 'boolean', 'default' => false ],
'pagedFormat' => [ 'type' => 'string', 'default' => '#separator_sa Page #page_number', 'localized' => true ],
'runShortcodes' => [ 'type' => 'boolean', 'default' => false ],
'crawlCleanup' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'feeds' => [
'global' => [ 'type' => 'boolean', 'default' => true ],
'globalComments' => [ 'type' => 'boolean', 'default' => false ],
'staticBlogPage' => [ 'type' => 'boolean', 'default' => true ],
'authors' => [ 'type' => 'boolean', 'default' => true ],
'postComments' => [ 'type' => 'boolean', 'default' => false ],
'search' => [ 'type' => 'boolean', 'default' => false ],
'attachments' => [ 'type' => 'boolean', 'default' => false ],
'archives' => [
'all' => [ 'type' => 'boolean', 'default' => false ],
'included' => [ 'type' => 'array', 'default' => [] ],
],
'taxonomies' => [
'all' => [ 'type' => 'boolean', 'default' => false ],
'included' => [ 'type' => 'array', 'default' => [ 'category' ] ],
],
'atom' => [ 'type' => 'boolean', 'default' => false ],
'rdf' => [ 'type' => 'boolean', 'default' => false ],
'paginated' => [ 'type' => 'boolean', 'default' => false ]
]
],
'unwantedBots' => [
'all' => [ 'type' => 'boolean', 'default' => false ],
'settings' => [
'googleAdsBot' => [ 'type' => 'boolean', 'default' => false ],
'openAiGptBot' => [ 'type' => 'boolean', 'default' => false ],
'commonCrawlCcBot' => [ 'type' => 'boolean', 'default' => false ],
'googleGeminiVertexAiBots' => [ 'type' => 'boolean', 'default' => false ]
]
],
'searchCleanup' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'settings' => [
'maxAllowedNumberOfChars' => [ 'type' => 'number', 'default' => 50 ],
'emojisAndSymbols' => [ 'type' => 'boolean', 'default' => false ],
'commonPatterns' => [ 'type' => 'boolean', 'default' => false ],
'redirectPrettyUrls' => [ 'type' => 'boolean', 'default' => false ],
'preventCrawling' => [ 'type' => 'boolean', 'default' => false ]
]
],
'blockArgs' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'optimizeUtmParameters' => [ 'type' => 'boolean', 'default' => false ],
'logsRetention' => [ 'type' => 'string', 'default' => '{"label":"1 week","value":"week"}' ]
],
'removeCategoryBase' => [ 'type' => 'boolean', 'default' => false ]
],
'archives' => [
'author' => [
'show' => [ 'type' => 'boolean', 'default' => true ],
'title' => [ 'type' => 'string', 'localized' => true, 'default' => '#author_name #separator_sa #site_title' ],
'metaDescription' => [ 'type' => 'string', 'localized' => true, 'default' => '#author_bio' ],
'advanced' => [
'robotsMeta' => [
'default' => [ 'type' => 'boolean', 'default' => true ],
'noindex' => [ 'type' => 'boolean', 'default' => false ],
'nofollow' => [ 'type' => 'boolean', 'default' => false ],
'noarchive' => [ 'type' => 'boolean', 'default' => false ],
'noimageindex' => [ 'type' => 'boolean', 'default' => false ],
'notranslate' => [ 'type' => 'boolean', 'default' => false ],
'nosnippet' => [ 'type' => 'boolean', 'default' => false ],
'noodp' => [ 'type' => 'boolean', 'default' => false ],
'maxSnippet' => [ 'type' => 'number', 'default' => -1 ],
'maxVideoPreview' => [ 'type' => 'number', 'default' => -1 ],
'maxImagePreview' => [ 'type' => 'string', 'default' => 'large' ]
],
'showDateInGooglePreview' => [ 'type' => 'boolean', 'default' => true ],
'showPostThumbnailInSearch' => [ 'type' => 'boolean', 'default' => true ],
'showMetaBox' => [ 'type' => 'boolean', 'default' => true ],
'keywords' => [ 'type' => 'string', 'localized' => true ]
]
],
'date' => [
'show' => [ 'type' => 'boolean', 'default' => true ],
'title' => [ 'type' => 'string', 'localized' => true, 'default' => '#archive_date #separator_sa #site_title' ],
'metaDescription' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'advanced' => [
'robotsMeta' => [
'default' => [ 'type' => 'boolean', 'default' => true ],
'noindex' => [ 'type' => 'boolean', 'default' => false ],
'nofollow' => [ 'type' => 'boolean', 'default' => false ],
'noarchive' => [ 'type' => 'boolean', 'default' => false ],
'noimageindex' => [ 'type' => 'boolean', 'default' => false ],
'notranslate' => [ 'type' => 'boolean', 'default' => false ],
'nosnippet' => [ 'type' => 'boolean', 'default' => false ],
'noodp' => [ 'type' => 'boolean', 'default' => false ],
'maxSnippet' => [ 'type' => 'number', 'default' => -1 ],
'maxVideoPreview' => [ 'type' => 'number', 'default' => -1 ],
'maxImagePreview' => [ 'type' => 'string', 'default' => 'large' ]
],
'showDateInGooglePreview' => [ 'type' => 'boolean', 'default' => true ],
'showPostThumbnailInSearch' => [ 'type' => 'boolean', 'default' => true ],
'showMetaBox' => [ 'type' => 'boolean', 'default' => true ],
'keywords' => [ 'type' => 'string', 'localized' => true ]
]
],
'search' => [
'show' => [ 'type' => 'boolean', 'default' => false ],
'title' => [ 'type' => 'string', 'localized' => true, 'default' => '#search_term #separator_sa #site_title' ],
'metaDescription' => [ 'type' => 'string', 'localized' => true, 'default' => '' ],
'advanced' => [
'robotsMeta' => [
'default' => [ 'type' => 'boolean', 'default' => false ],
'noindex' => [ 'type' => 'boolean', 'default' => true ],
'nofollow' => [ 'type' => 'boolean', 'default' => false ],
'noarchive' => [ 'type' => 'boolean', 'default' => false ],
'noimageindex' => [ 'type' => 'boolean', 'default' => false ],
'notranslate' => [ 'type' => 'boolean', 'default' => false ],
'nosnippet' => [ 'type' => 'boolean', 'default' => false ],
'noodp' => [ 'type' => 'boolean', 'default' => false ],
'maxSnippet' => [ 'type' => 'number', 'default' => -1 ],
'maxVideoPreview' => [ 'type' => 'number', 'default' => -1 ],
'maxImagePreview' => [ 'type' => 'string', 'default' => 'large' ]
],
'showDateInGooglePreview' => [ 'type' => 'boolean', 'default' => true ],
'showPostThumbnailInSearch' => [ 'type' => 'boolean', 'default' => true ],
'showMetaBox' => [ 'type' => 'boolean', 'default' => true ],
'keywords' => [ 'type' => 'string', 'localized' => true ]
]
]
]
],
'searchStatistics' => [
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page' ] ],
]
],
'tools' => [
'robots' => [
'enable' => [ 'type' => 'boolean', 'default' => false ],
'rules' => [ 'type' => 'array', 'default' => [] ],
'robotsDetected' => [ 'type' => 'boolean', 'default' => true ],
],
'importExport' => [
'backup' => [
'lastTime' => [ 'type' => 'string' ],
'data' => [ 'type' => 'string' ],
]
]
],
'deprecated' => [
'breadcrumbs' => [
'enable' => [ 'type' => 'boolean', 'default' => true ]
],
'searchAppearance' => [
'global' => [
'descriptionFormat' => [ 'type' => 'string' ],
'schema' => [
'enableSchemaMarkup' => [ 'type' => 'boolean', 'default' => true ]
]
],
'advanced' => [
'autogenerateDescriptions' => [ 'type' => 'boolean', 'default' => true ],
'runShortcodesInDescription' => [ 'type' => 'boolean', 'default' => true ], // TODO: Remove this in a future update.
'useContentForAutogeneratedDescriptions' => [ 'type' => 'boolean', 'default' => false ],
'excludePosts' => [ 'type' => 'array', 'default' => [] ],
'excludeTerms' => [ 'type' => 'array', 'default' => [] ],
'noPaginationForCanonical' => [ 'type' => 'boolean', 'default' => true ]
]
],
'sitemap' => [
'general' => [
'advancedSettings' => [
'dynamic' => [ 'type' => 'boolean', 'default' => true ]
]
]
]
],
'writingAssistant' => [
'postTypes' => [
'all' => [ 'type' => 'boolean', 'default' => true ],
'included' => [ 'type' => 'array', 'default' => [ 'post', 'page' ] ],
]
]
// phpcs:enable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
];
/**
* The Construct method.
*
* @since 4.0.0
*
* @param string $optionsName An array of options.
*/
public function __construct( $optionsName = 'aioseo_options' ) {
$this->optionsName = $optionsName;
$this->init();
add_action( 'shutdown', [ $this, 'save' ] );
}
/**
* Initializes the options.
*
* @since 4.0.0
*
* @return void
*/
public function init() {
$this->setInitialDefaults();
add_action( 'init', [ $this, 'translateDefaults' ] );
$this->setDbOptions();
add_action( 'wp_loaded', [ $this, 'maybeFlushRewriteRules' ] );
}
/**
* Sets the DB options to the class after merging in new defaults and dropping unknown values.
*
* @since 4.0.14
*
* @return void
*/
public function setDbOptions() {
// Refactor options.
$this->defaultsMerged = array_replace_recursive( $this->defaults, $this->defaultsMerged );
$dbOptions = $this->getDbOptions( $this->optionsName );
$options = array_replace_recursive(
$this->defaultsMerged,
$this->addValueToValuesArray( $this->defaultsMerged, $dbOptions )
);
aioseo()->core->optionsCache->setOptions( $this->optionsName, apply_filters( 'aioseo_get_options', $options ) );
// Get the localized options.
$dbOptionsLocalized = get_option( $this->optionsName . '_localized' );
if ( empty( $dbOptionsLocalized ) ) {
$dbOptionsLocalized = [];
}
$this->localized = $dbOptionsLocalized;
}
/**
* Sets the initial defaults that can't be defined in the property because of PHP 5.4.
*
* @since 4.1.4
*
* @return void
*/
protected function setInitialDefaults() {
static $hasInitialized = false;
if ( $hasInitialized ) {
return;
}
$hasInitialized = true;
$this->defaults['searchAppearance']['global']['schema']['organizationLogo']['default'] = aioseo()->helpers->getSiteLogoUrl() ? aioseo()->helpers->getSiteLogoUrl() : '';
$this->defaults['advanced']['emailSummary']['recipients']['default'] = [
[
'email' => get_bloginfo( 'admin_email' ),
'frequency' => 'monthly',
]
];
}
/**
* For our defaults array, some options need to be translated, so we do that here.
*
* @since 4.0.0
*
* @return void
*/
public function translateDefaults() {
static $hasInitialized = false;
if ( $hasInitialized ) {
return;
}
$hasInitialized = true;
$default = sprintf( '{"label":"%1$s","value":"default"}', __( 'default', 'all-in-one-seo-pack' ) );
$this->defaults['sitemap']['general']['advancedSettings']['priority']['homePage']['priority']['default'] = $default;
$this->defaults['sitemap']['general']['advancedSettings']['priority']['homePage']['frequency']['default'] = $default;
$this->defaults['sitemap']['general']['advancedSettings']['priority']['postTypes']['priority']['default'] = $default;
$this->defaults['sitemap']['general']['advancedSettings']['priority']['postTypes']['frequency']['default'] = $default;
$this->defaults['sitemap']['general']['advancedSettings']['priority']['taxonomies']['priority']['default'] = $default;
$this->defaults['sitemap']['general']['advancedSettings']['priority']['taxonomies']['frequency']['default'] = $default;
$this->defaults['breadcrumbs']['homepageLabel']['default'] = __( 'Home', 'all-in-one-seo-pack' );
$this->defaults['breadcrumbs']['archiveFormat']['default'] = sprintf( '%1$s #breadcrumb_archive_post_type_name', __( 'Archives for', 'all-in-one-seo-pack' ) );
$this->defaults['breadcrumbs']['searchResultFormat']['default'] = sprintf( '%1$s \'#breadcrumb_search_string\'', __( 'Search Results for', 'all-in-one-seo-pack' ) );
$this->defaults['breadcrumbs']['errorFormat404']['default'] = __( '404 - Page Not Found', 'all-in-one-seo-pack' );
}
/**
* Sanitizes, then saves the options to the database.
*
* @since 4.0.0
*
* @param array $options An array of options to sanitize, then save.
* @return void
*/
public function sanitizeAndSave( $options ) {
$sitemapOptions = ! empty( $options['sitemap'] ) ? $options['sitemap'] : null;
$oldSitemapOptions = aioseo()->options->sitemap->all();
$generalSitemapOptions = ! empty( $options['sitemap']['general'] ) ? $options['sitemap']['general'] : null;
$oldGeneralSitemapOptions = aioseo()->options->sitemap->general->all();
$deprecatedGeneralSitemapOptions = ! empty( $options['deprecated']['sitemap']['general'] )
? $options['deprecated']['sitemap']['general']
: null;
$oldDeprecatedGeneralSitemapOptions = aioseo()->options->deprecated->sitemap->general->all();
$oldPhoneOption = aioseo()->options->searchAppearance->global->schema->phone;
$phoneNumberOptions = isset( $options['searchAppearance']['global']['schema']['phone'] )
? $options['searchAppearance']['global']['schema']['phone']
: null;
$oldHtmlSitemapUrl = aioseo()->options->sitemap->html->pageUrl;
$logsRetention = isset( $options['searchAppearance']['advanced']['blockArgs']['logsRetention'] ) ? $options['searchAppearance']['advanced']['blockArgs']['logsRetention'] : null;
$oldLogsRetention = aioseo()->options->searchAppearance->advanced->blockArgs->logsRetention;
// Remove category base.
$removeCategoryBase = isset( $options['searchAppearance']['advanced']['removeCategoryBase'] ) ? $options['searchAppearance']['advanced']['removeCategoryBase'] : null;
$removeCategoryBaseOld = aioseo()->options->searchAppearance->advanced->removeCategoryBase;
$options = $this->maybeRemoveUnfilteredHtmlFields( $options );
$this->init();
if ( ! is_array( $options ) ) {
return;
}
$this->sanitizeEmailSummary( $options );
// First, recursively replace the new options into the cached state.
// It's important we use the helper method since we want to replace populated arrays with empty ones if needed (when a setting was cleared out).
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$dbOptions = aioseo()->helpers->arrayReplaceRecursive(
$cachedOptions,
$this->addValueToValuesArray( $cachedOptions, $options, [], true )
);
// Now, we must also intersect both arrays to delete any individual keys that were unset.
// We must do this because, while arrayReplaceRecursive will update the values for keys or empty them out,
// it will keys that aren't present in the replacement array unaffected in the target array.
$dbOptions = aioseo()->helpers->arrayIntersectRecursive(
$dbOptions,
$this->addValueToValuesArray( $cachedOptions, $options, [], true ),
'value'
);
if ( isset( $options['social']['profiles']['additionalUrls'] ) ) {
$dbOptions['social']['profiles']['additionalUrls'] = preg_replace( '/\h/', "\n", (string) $options['social']['profiles']['additionalUrls'] );
}
$newOptions = ! empty( $options['sitemap']['html'] ) ? $options['sitemap']['html'] : null;
if ( ! empty( $newOptions ) && aioseo()->options->sitemap->html->enable ) {
$newOptions = ! empty( $options['sitemap']['html'] ) ? $options['sitemap']['html'] : null;
$pageUrl = wp_parse_url( $newOptions['pageUrl'] );
$path = ! empty( $pageUrl['path'] ) ? untrailingslashit( $pageUrl['path'] ) : '';
if ( $path ) {
$existingPage = get_page_by_path( $path, OBJECT );
if ( is_object( $existingPage ) ) {
// If the page exists, don't override the previous URL.
$options['sitemap']['html']['pageUrl'] = $oldHtmlSitemapUrl;
}
}
}
// Update the cache state.
aioseo()->core->optionsCache->setOptions( $this->optionsName, $dbOptions );
// Update localized options.
update_option( $this->optionsName . '_localized', $this->localized );
// Finally, save the new values to the DB.
$this->save( true );
// If phone settings have changed, let's see if we need to dump the phone number notice.
if (
$phoneNumberOptions &&
$phoneNumberOptions !== $oldPhoneOption
) {
$notification = Models\Notification::getNotificationByName( 'v3-migration-schema-number' );
if ( $notification->exists() ) {
Models\Notification::deleteNotificationByName( 'v3-migration-schema-number' );
}
}
// If sitemap settings were changed, static files need to be regenerated.
if (
! empty( $deprecatedGeneralSitemapOptions ) &&
! empty( $generalSitemapOptions )
) {
if (
(
aioseo()->helpers->arraysDifferent( $oldGeneralSitemapOptions, $generalSitemapOptions ) ||
aioseo()->helpers->arraysDifferent( $oldDeprecatedGeneralSitemapOptions, $deprecatedGeneralSitemapOptions )
) &&
$generalSitemapOptions['advancedSettings']['enable'] &&
! $deprecatedGeneralSitemapOptions['advancedSettings']['dynamic']
) {
aioseo()->sitemap->scheduleRegeneration();
}
}
// Add or remove schedule for clearing crawl cleanup logs.
if ( ! empty( $logsRetention ) && $oldLogsRetention !== $logsRetention ) {
aioseo()->crawlCleanup->scheduleClearingLogs();
}
if ( ! empty( $sitemapOptions ) ) {
aioseo()->searchStatistics->sitemap->maybeSync( $oldSitemapOptions, $sitemapOptions );
}
if (
null !== $removeCategoryBase &&
$removeCategoryBase !== $removeCategoryBaseOld
) {
aioseo()->options->flushRewriteRules();
}
// This is required in order for the Pro options to be refreshed before they save data again.
$this->refresh();
}
/**
* Sanitizes the `emailSummary` option.
*
* @since 4.7.2
*
* @param array $options All options, passed by reference.
* @return void
*/
private function sanitizeEmailSummary( &$options ) {
foreach ( ( $options['advanced']['emailSummary']['recipients'] ?? [] ) as $k => &$recipient ) {
$recipient['email'] = is_email( $recipient['email'] );
// Remove empty emails.
if ( empty( $recipient['email'] ) ) {
unset( $options['advanced']['emailSummary']['recipients'][ $k ] );
continue;
}
// Remove duplicate emails with the same frequency.
foreach ( $options['advanced']['emailSummary']['recipients'] as $k2 => $recipient2 ) {
if (
$k !== $k2 &&
$recipient['email'] === $recipient2['email'] &&
$recipient['frequency'] === $recipient2['frequency']
) {
unset( $options['advanced']['emailSummary']['recipients'][ $k ] );
break;
}
}
}
}
/**
* If the user does not have access to unfiltered HTML, we need to remove them from saving.
*
* @since 4.0.0
*
* @param array $options An array of options.
* @return array An array of options.
*/
private function maybeRemoveUnfilteredHtmlFields( $options ) {
if ( current_user_can( 'unfiltered_html' ) ) {
return $options;
}
if (
! empty( $options['webmasterTools'] ) &&
isset( $options['webmasterTools']['miscellaneousVerification'] )
) {
unset( $options['webmasterTools']['miscellaneousVerification'] );
}
if (
! empty( $options['rssContent'] ) &&
isset( $options['rssContent']['before'] )
) {
unset( $options['rssContent']['before'] );
}
if (
! empty( $options['rssContent'] ) &&
isset( $options['rssContent']['after'] )
) {
unset( $options['rssContent']['after'] );
}
return $options;
}
/**
* Indicate we need to flush rewrite rules on next load.
*
* @since 4.0.17
*
* @return void
*/
public function flushRewriteRules() {
update_option( 'aioseo_flush_rewrite_rules_flag', true );
}
/**
* Flush rewrite rules if needed.
*
* @since 4.0.17
*
* @return void
*/
public function maybeFlushRewriteRules() {
if ( get_option( 'aioseo_flush_rewrite_rules_flag' ) ) {
flush_rewrite_rules();
delete_option( 'aioseo_flush_rewrite_rules_flag' );
}
}
} home/xbodynamge/dev/wp-content/plugins/all-in-one-seo-pack/app/Common/Traits/Options.php 0000644 00000067142 15114647145 0025265 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Traits;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Options trait.
*
* @since 4.0.0
*/
trait Options {
/**
* Whether or not this instance is a clone.
*
* @since 4.1.4
*
* @var boolean
*/
public $isClone = false;
/**
* Whether or not the options need to be saved to the DB.
*
* @since 4.1.4
*
* @var string
*/
public $shouldSave = false;
/**
* The name to lookup the options with.
*
* @since 4.0.0
*
* @var string
*/
public $optionsName = '';
/**
* Holds the localized options.
*
* @since 4.0.0
*
* @var array
*/
public $localized = [];
/**
* The group key we are working with.
*
* @since 4.0.0
*
* @var string|null
*/
protected $groupKey = null;
/**
* Allows us to create unlimited number of sub groups.
* Like so: options->breadcrumbs->templates->taxonomies->tags->template
*
* @since 4.0.0
*
* @var array
*/
protected $subGroups = [];
/**
* Any arguments associated with a dynamic method.
*
* @since 4.0.0
*
* @var array
*/
protected $arguments = [];
/**
* The value to set on an option.
*
* @since 4.0.0
*
* @var mixed
*/
protected $value = null;
/**
* Holds all the defaults after they have been merged.
*
* @since 4.0.0
*
* @var array
*/
protected $defaultsMerged = [];
/**
* Holds a redirect link or slug.
*
* @since 4.0.17
*
* @var string
*/
protected $screenRedirection = '';
/**
* Retrieve an option or null if missing.
*
* @since 4.0.0
*
* @param string $name The name of the property that is missing on the class.
* @param array $arguments The arguments passed into the method.
* @return mixed The value from the options or default/null.
*/
public function __call( $name, $arguments = [] ) {
if ( $this->setGroupKey( $name, $arguments ) ) {
return $this;
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = $cachedOptions[ $this->groupKey ];
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = $defaults[ $subGroup ];
}
}
if ( ! isset( $defaults[ $name ] ) ) {
$this->resetGroups();
return ! empty( $this->arguments[0] )
? $this->arguments[0]
: $this->getDefault( $name, false );
}
if ( empty( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
$value = isset( $cachedOptions[ $this->groupKey ][ $name ]['value'] )
? $cachedOptions[ $this->groupKey ][ $name ]['value']
: (
! empty( $this->arguments[0] )
? $this->arguments[0]
: $this->getDefault( $name, false )
);
$this->resetGroups();
return $value;
}
/**
* Retrieve an option or null if missing.
*
* @since 4.0.0
*
* @param string $name The name of the property that is missing on the class.
* @return mixed The value from the options or default/null.
*/
public function __get( $name ) {
if ( 'type' === $name ) {
$name = '_aioseo_type';
}
if ( $this->setGroupKey( $name ) ) {
return $this;
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = $cachedOptions[ $this->groupKey ];
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = $defaults[ $subGroup ];
}
}
if ( ! isset( $defaults[ $name ] ) ) {
$default = $this->getDefault( $name, false );
$this->resetGroups();
return $default;
}
if ( ! isset( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
$value = $this->getDefault( $name, false );
if ( isset( $defaults[ $name ]['value'] ) ) {
$preserveHtml = ! empty( $defaults[ $name ]['preserveHtml'] );
if ( $preserveHtml ) {
if ( is_array( $defaults[ $name ]['value'] ) ) {
foreach ( $defaults[ $name ]['value'] as $k => $v ) {
$defaults[ $name ]['value'][ $k ] = html_entity_decode( $v, ENT_NOQUOTES );
}
} else {
$defaults[ $name ]['value'] = html_entity_decode( $defaults[ $name ]['value'], ENT_NOQUOTES );
}
}
$value = $defaults[ $name ]['value'];
// Localized value.
if ( isset( $defaults[ $name ]['localized'] ) ) {
$localizedKey = $this->groupKey;
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$localizedKey .= '_' . $subGroup;
}
}
$localizedKey .= '_' . $name;
if ( ! empty( $this->localized[ $localizedKey ] ) ) {
$value = $this->localized[ $localizedKey ];
// We need to rebuild the keywords as a json string.
if ( 'keywords' === $name ) {
$keywords = explode( ',', $value );
foreach ( $keywords as $k => $keyword ) {
$keywords[ $k ] = [
'label' => $keyword,
'value' => $keyword
];
}
$value = wp_json_encode( $keywords );
}
}
}
}
$this->resetGroups();
return $value;
}
/**
* Sets the option value and saves to the database.
*
* @since 4.0.0
*
* @param string $name The name of the option.
* @param mixed $value The value to set.
* @return void
*/
public function __set( $name, $value ) {
if ( $this->setGroupKey( $name, null, $value ) ) {
return $this;
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = json_decode( wp_json_encode( $cachedOptions[ $this->groupKey ] ), true );
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = &$defaults[ $subGroup ];
}
}
if ( ! isset( $defaults[ $name ] ) ) {
$default = $this->getDefault( $name, false );
$this->resetGroups();
return $default;
}
if ( empty( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
$preserveHtml = ! empty( $defaults[ $name ]['preserveHtml'] );
$localized = ! empty( $defaults[ $name ]['localized'] );
$defaults[ $name ]['value'] = $this->sanitizeField( $this->value, $defaults[ $name ]['type'], $preserveHtml );
if ( $localized ) {
$localizedKey = $this->groupKey;
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$localizedKey .= '_' . $subGroup;
}
}
$localizedKey .= '_' . $name;
$localizedValue = $defaults[ $name ]['value'];
if ( 'keywords' === $name ) {
$keywords = json_decode( $localizedValue ) ? json_decode( $localizedValue ) : [];
foreach ( $keywords as $k => $keyword ) {
$keywords[ $k ] = $keyword->value;
}
$localizedValue = implode( ',', $keywords );
}
$this->localized[ $localizedKey ] = $localizedValue;
update_option( $this->optionsName . '_localized', $this->localized );
}
$originalDefaults = json_decode( wp_json_encode( $cachedOptions[ $this->groupKey ] ), true );
$pointer = &$originalDefaults; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
foreach ( $this->subGroups as $subGroup ) {
$pointer = &$pointer[ $subGroup ];
}
$pointer = $defaults;
$cachedOptions[ $this->groupKey ] = $originalDefaults;
aioseo()->core->optionsCache->setOptions( $this->optionsName, $cachedOptions );
$this->resetGroups();
$this->update();
}
/**
* Checks if an option is set or returns null if not.
*
* @since 4.0.0
*
* @param string $name The name of the option.
* @return mixed True or null.
*/
public function __isset( $name ) {
if ( $this->setGroupKey( $name ) ) {
return $this;
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = $cachedOptions[ $this->groupKey ];
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = &$defaults[ $subGroup ];
}
}
if ( ! isset( $defaults[ $name ] ) ) {
$this->resetGroups();
return false;
}
if ( empty( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
$value = isset( $defaults[ $name ]['value'] )
? false === empty( $defaults[ $name ]['value'] )
: false;
$this->resetGroups();
return $value;
}
/**
* Unsets the option value and saves to the database.
*
* @since 4.0.0
*
* @param string $name The name of the option.
* @return void
*/
public function __unset( $name ) {
if ( $this->setGroupKey( $name ) ) {
return $this;
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = json_decode( wp_json_encode( $cachedOptions[ $this->groupKey ] ), true );
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = &$defaults[ $subGroup ];
}
}
if ( ! isset( $defaults[ $name ] ) ) {
$this->groupKey = null;
$this->subGroups = [];
return;
}
if ( empty( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
if ( ! isset( $defaults[ $name ]['value'] ) ) {
return;
}
unset( $defaults[ $name ]['value'] );
$cachedOptions[ $this->groupKey ] = $defaults;
aioseo()->core->optionsCache->setOptions( $this->optionsName, $cachedOptions );
$this->resetGroups();
$this->update();
}
/**
* Retrieves all options.
*
* @since 4.0.0
*
* @param array $include Keys to include.
* @param array $exclude Keys to exclude.
* @return array An array of options.
*/
public function all( $include = [], $exclude = [] ) {
$originalGroupKey = $this->groupKey;
$originalSubGroups = $this->subGroups;
// Make sure our dynamic options have loaded.
$this->init();
// Refactor options.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$refactored = $this->convertOptionsToValues( $cachedOptions );
$this->groupKey = null;
if ( ! $originalGroupKey ) {
return $this->allFiltered( $refactored, $include, $exclude );
}
if ( empty( $originalSubGroups ) ) {
$all = $refactored[ $originalGroupKey ];
return $this->allFiltered( $all, $include, $exclude );
}
$returnable = &$refactored[ $originalGroupKey ]; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
foreach ( $originalSubGroups as $subGroup ) {
$returnable = &$returnable[ $subGroup ];
}
$this->resetGroups();
return $this->allFiltered( $returnable, $include, $exclude );
}
/**
* Reset the current option to the defaults.
*
* @since 4.0.0
*
* @param array $include Keys to include.
* @param array $exclude Keys to exclude.
* @return void
*/
public function reset( $include = [], $exclude = [] ) {
$originalGroupKey = $this->groupKey;
$originalSubGroups = $this->subGroups;
// Make sure our dynamic options have loaded.
$this->init();
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
// If we don't have a group key set, it means we want to reset everything.
if ( empty( $originalGroupKey ) ) {
$groupKeys = array_keys( $cachedOptions );
foreach ( $groupKeys as $groupKey ) {
$this->groupKey = $groupKey;
$this->reset();
}
// Since we just finished resetting everything, we can return early.
return;
}
// If we need to set a sub-group, do that now.
$keys = array_merge( [ $originalGroupKey ], $originalSubGroups );
$defaults = json_decode( wp_json_encode( $cachedOptions[ $originalGroupKey ] ), true );
if ( ! empty( $originalSubGroups ) ) {
foreach ( $originalSubGroups as $subGroup ) {
$defaults = $defaults[ $subGroup ];
}
}
// Refactor options.
$resetValues = $this->resetValues( $defaults, $this->defaultsMerged, $keys, $include, $exclude );
// We need to call our helper method instead of the built-in array_replace_recursive() function here because we want values to be replaced with empty arrays.
$defaults = aioseo()->helpers->arrayReplaceRecursive( $defaults, $resetValues );
$originalDefaults = json_decode( wp_json_encode( $cachedOptions[ $originalGroupKey ] ), true );
$pointer = &$originalDefaults; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
foreach ( $originalSubGroups as $subGroup ) {
$pointer = &$pointer[ $subGroup ];
}
$pointer = $defaults;
$cachedOptions[ $originalGroupKey ] = $originalDefaults;
aioseo()->core->optionsCache->setOptions( $this->optionsName, $cachedOptions );
$this->resetGroups();
$this->update();
}
/**
* Resets all values in a group.
*
* @since 4.0.0
*
* @param array $defaults The defaults array we are currently working with.
* @param array $values The values to adjust.
* @param array $keys Parent keys for the current group we are parsing.
* @param array $include Keys to include.
* @param array $exclude Keys to exclude.
* @return array The modified values.
*/
protected function resetValues( $values, $defaults, $keys = [], $include = [], $exclude = [] ) {
$values = $this->allFiltered( $values, $include, $exclude );
foreach ( $values as $key => $value ) {
$option = $this->isAnOption( $key, $defaults, $keys );
if ( $option ) {
$values[ $key ]['value'] = isset( $values[ $key ]['default'] ) ? $values[ $key ]['default'] : null;
continue;
}
$keys[] = $key;
$values[ $key ] = $this->resetValues( $value, $defaults, $keys );
array_pop( $keys );
}
return $values;
}
/**
* Checks if the current group has an option or group.
*
* @since 4.0.0
*
* @param string $optionOrGroup The option or group to look for.
* @param bool $resetGroups Whether or not to reset the groups after.
* @return bool True if it does, false if not.
*/
public function has( $optionOrGroup = '', $resetGroups = true ) {
if ( 'type' === $optionOrGroup ) {
$optionOrGroup = '_aioseo_type';
}
$originalGroupKey = $this->groupKey;
$originalSubGroups = $this->subGroups;
static $hasInitialized = false;
if ( ! $hasInitialized ) {
$hasInitialized = true;
$this->init();
}
// If we need to set a sub-group, do that now.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$defaults = $originalGroupKey ? $cachedOptions[ $originalGroupKey ] : $cachedOptions;
if ( ! empty( $originalSubGroups ) ) {
foreach ( $originalSubGroups as $subGroup ) {
$defaults = $defaults[ $subGroup ];
}
}
if ( $resetGroups ) {
$this->resetGroups();
}
if ( ! empty( $defaults[ $optionOrGroup ] ) ) {
return true;
}
return false;
}
/**
* Filters the results based on passed in array.
*
* @since 4.0.0
*
* @param array $all All the options to filter.
* @param array $include Keys to include.
* @param array $exclude Keys to exclude.
* @return array The filtered options.
*/
private function allFiltered( $all, $include, $exclude ) {
if ( ! empty( $include ) ) {
return array_intersect_ukey( $all, $include, function ( $key1, $key2 ) use ( $include ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
if ( in_array( $key1, $include, true ) ) {
return 0;
}
return -1;
} );
}
if ( ! empty( $exclude ) ) {
return array_diff_ukey( $all, $exclude, function ( $key1, $key2 ) use ( $exclude ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
if ( ! in_array( $key1, $exclude, true ) ) {
return 0;
}
return -1;
} );
}
return $all;
}
/**
* Gets the default value for an option.
*
* @since 4.0.0
*
* @param string $name The option name.
* @return mixed The default value.
*/
public function getDefault( $name, $resetGroups = true ) {
$defaults = $this->defaultsMerged[ $this->groupKey ];
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
if ( empty( $defaults[ $subGroup ] ) ) {
return null;
}
$defaults = $defaults[ $subGroup ];
}
}
if ( $resetGroups ) {
$this->resetGroups();
}
if ( ! isset( $defaults[ $name ] ) ) {
return null;
}
if ( empty( $defaults[ $name ]['type'] ) ) {
return $this->setSubGroup( $name );
}
return isset( $defaults[ $name ]['default'] )
? $defaults[ $name ]['default']
: null;
}
/**
* Gets the defaults options.
*
* @since 4.1.3
*
* @return array An array of dafults.
*/
public function getDefaults() {
return $this->defaults;
}
/**
* Updates the options in the database.
*
* @since 4.0.0
*
* @param string $optionsName An optional option name to update.
* @param string $defaults The defaults to filter the options by.
* @param array|null $options An optional options array.
* @return void
*/
public function update( $optionsName = null, $defaults = null, $options = null ) {
$optionsName = empty( $optionsName ) ? $this->optionsName : $optionsName;
$defaults = empty( $defaults ) ? $this->defaults : $defaults;
// First, we need to filter our options.
$options = $this->filterOptions( $defaults, $options );
// Refactor options.
$refactored = $this->convertOptionsToValues( $options );
$this->resetGroups();
// The following needs to happen here (possibly a clone) as well as in the main instance.
$originalInstance = $this->getOriginalInstance();
// Update the DB options.
aioseo()->core->optionsCache->setDb( $optionsName, $refactored );
// Force a save here and in the main class.
$this->shouldSave = true;
$originalInstance->shouldSave = true;
}
/**
* Updates the options in the database.
*
* @since 4.1.4
*
* @param boolean $force Whether or not to force an immediate save.
* @param string $optionsName An optional option name to update.
* @param string $defaults The defaults to filter the options by.
* @return void
*/
public function save( $force = false, $optionsName = null, $defaults = null ) {
if ( ! $this->shouldSave && ! $force ) {
return;
}
$optionsName = empty( $optionsName ) ? $this->optionsName : $optionsName;
$defaults = empty( $defaults ) ? $this->defaults : $defaults;
$this->update( $optionsName );
// First, we need to filter our options.
$options = $this->filterOptions( $defaults );
// Refactor options.
$refactored = $this->convertOptionsToValues( $options );
$this->resetGroups();
update_option( $optionsName, wp_json_encode( $refactored ) );
}
/**
* Filter options to match our defaults.
*
* @since 4.0.0
*
* @param array $defaults The defaults to use in filtering.
* @param array|null $options An optional options array.
* @return array An array of filtered options.
*/
public function filterOptions( $defaults, $options = null ) {
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$options = ! empty( $options ) ? $options : json_decode( wp_json_encode( $cachedOptions ), true );
return $this->filterRecursively( $options, $defaults );
}
/**
* Filters options in a loop.
*
* @since 4.0.0
*
* @param array $options An array of options to filter.
* @param array $defaults An array of defaults to filter against.
* @return array A filtered array of options.
*/
public function filterRecursively( $options, $defaults ) {
if ( ! is_array( $options ) ) {
return $options;
}
foreach ( $options as $key => $value ) {
if ( ! isset( $defaults[ $key ] ) ) {
unset( $options[ $key ] );
continue;
}
if ( ! isset( $value['type'] ) ) {
$options[ $key ] = $this->filterRecursively( $options[ $key ], $defaults[ $key ] );
continue;
}
}
return $options;
}
/**
* Sanitizes the value before allowing it to be saved.
*
* @since 4.0.0
*
* @param mixed $value The value to sanitize.
* @param string $type The type of sanitization to do.
* @return mixed The sanitized value.
*/
public function sanitizeField( $value, $type, $preserveHtml = false ) {
switch ( $type ) {
case 'boolean':
return (bool) $value;
case 'html':
return sanitize_textarea_field( $value );
case 'string':
return sanitize_text_field( $value );
case 'number':
return intval( $value );
case 'array':
$array = [];
foreach ( (array) $value as $k => $v ) {
if ( is_array( $v ) ) {
$array[ $k ] = $this->sanitizeField( $v, 'array' );
continue;
}
$array[ $k ] = sanitize_text_field( $preserveHtml ? htmlspecialchars( $v, ENT_NOQUOTES, 'UTF-8' ) : $v );
}
return $array;
case 'float':
return floatval( $value );
}
}
/**
* Checks to see if we need to set the group key. If so, will return true.
*
* @since 4.0.0
*
* @param string $name The name of the option to set.
* @param array $arguments Any arguments needed if this was a method called.
* @param mixed $value The value if we are setting an option.
* @return boolean Whether or not we need to set the group key.
*/
private function setGroupKey( $name, $arguments = null, $value = null ) {
$this->arguments = $arguments;
$this->value = $value;
if ( empty( $this->groupKey ) ) {
$groups = array_keys( $this->defaultsMerged );
if ( in_array( $name, $groups, true ) ) {
$this->groupKey = $name;
return true;
}
$this->groupKey = $groups[0];
}
return false;
}
/**
* Sets the sub group key. Will set and return the instance.
*
* @since 4.0.0
*
* @param string $name The name of the option to set.
* @param array $arguments Any arguments needed if this was a method called.
* @param mixed $value The value if we are setting an option.
* @return object The options object.
*/
private function setSubGroup( $name, $arguments = null, $value = null ) {
if ( ! is_null( $arguments ) ) {
$this->arguments = $arguments;
}
if ( ! is_null( $value ) ) {
$this->value = $value;
}
$defaults = $this->defaultsMerged[ $this->groupKey ];
if ( ! empty( $this->subGroups ) ) {
foreach ( $this->subGroups as $subGroup ) {
$defaults = $defaults[ $subGroup ];
}
}
$groups = array_keys( $defaults );
if ( in_array( $name, $groups, true ) ) {
$this->subGroups[] = $name;
}
return $this;
}
/**
* Reset groups.
*
* @since 4.0.0
*
* @return void
*/
protected function resetGroups() {
$this->groupKey = null;
$this->subGroups = [];
}
/**
* Converts an associative array of values into a structure
* that works with our defaults.
*
* @since 4.0.0
*
* @param array $defaults The defaults array we are currently working with.
* @param array $values The values to adjust.
* @param array $keys Parent keys for the current group we are parsing.
* @param bool $sanitize Whether or not we should sanitize the value.
* @return array The modified values.
*/
protected function addValueToValuesArray( $defaults, $values, $keys = [], $sanitize = false ) {
foreach ( $values as $key => $value ) {
$option = $this->isAnOption( $key, $defaults, $keys );
if ( $option ) {
$preserveHtml = ! empty( $option['preserveHtml'] );
$newValue = $sanitize ? $this->sanitizeField( $value, $option['type'], $preserveHtml ) : $value;
$values[ $key ] = [
'value' => $newValue
];
// If this is a localized string, let's save it to our localized options.
if ( $sanitize && ! empty( $option['localized'] ) ) {
$localizedKey = '';
foreach ( $keys as $k ) {
$localizedKey .= $k . '_';
}
$localizedKey .= $key;
$localizedValue = $newValue;
if ( 'keywords' === $key ) {
$keywords = json_decode( $localizedValue ) ? json_decode( $localizedValue ) : [];
foreach ( $keywords as $k => $keyword ) {
$keywords[ $k ] = $keyword->value;
}
$localizedValue = implode( ',', $keywords );
}
$this->localized[ $localizedKey ] = $localizedValue;
}
continue;
}
if ( ! is_array( $value ) ) {
continue;
}
$keys[] = $key;
$values[ $key ] = $this->addValueToValuesArray( $defaults, $value, $keys, $sanitize );
array_pop( $keys );
}
return $values;
}
/**
* Our options array has values (or defaults).
* This method converts them to how we would store them
* in the DB.
*
* @since 4.0.0
*
* @param array $options The options array.
* @return array The converted options array.
*/
public function convertOptionsToValues( $options, $optionKey = 'type' ) {
foreach ( $options as $key => $value ) {
if ( ! is_array( $value ) ) {
continue;
}
if ( ! isset( $value[ $optionKey ] ) ) {
$options[ $key ] = $this->convertOptionsToValues( $value, $optionKey );
continue;
}
$options[ $key ] = null;
if ( isset( $value['value'] ) ) {
$preserveHtml = ! empty( $value['preserveHtml'] );
if ( $preserveHtml ) {
if ( is_array( $value['value'] ) ) {
foreach ( $value['value'] as $k => $v ) {
$value['value'][ $k ] = html_entity_decode( $v, ENT_NOQUOTES );
}
} else {
$value['value'] = html_entity_decode( $value['value'], ENT_NOQUOTES );
}
}
$options[ $key ] = $value['value'];
continue;
}
if ( isset( $value['default'] ) ) {
$options[ $key ] = $value['default'];
}
}
return $options;
}
/**
* This checks to see if the current array/option is really an option
* and not just another parent with a subgroup.
*
* @since 4.0.0
*
* @param string $key The current array key we are working with.
* @param array $defaults The defaults array to check against.
* @param array $keys The parent keys to loop through.
* @return bool Whether or not this is an option.
*/
private function isAnOption( $key, $defaults, $keys ) {
if ( ! empty( $keys ) ) {
foreach ( $keys as $k ) {
$defaults = isset( $defaults[ $k ] ) ? $defaults[ $k ] : [];
}
}
if ( isset( $defaults[ $key ]['type'] ) ) {
return $defaults[ $key ];
}
return false;
}
/**
* Refreshes the options from the database.
*
* We need this during the migration to update through clones.
*
* @since 4.0.0
*
* @return void
*/
public function refresh() {
// Reset DB options to clear the cache.
aioseo()->core->optionsCache->resetDb();
$this->init();
}
/**
* Returns the DB options.
*
* @since 4.1.4
*
* @param string $optionsName The options name.
* @return array The options.
*/
public function getDbOptions( $optionsName ) {
$cache = aioseo()->core->optionsCache->getDb( $optionsName );
if ( empty( $cache ) ) {
$options = json_decode( get_option( $optionsName ), true );
$options = ! empty( $options ) ? $options : [];
// Set the cache.
aioseo()->core->optionsCache->setDb( $optionsName, $options );
}
return aioseo()->core->optionsCache->getDb( $optionsName );
}
/**
* In order to not have a conflict, we need to return a clone.
*
* @since 4.0.0
*
* @param bool $reInitialize Whether to reinitialize on the clone.
* @return object The cloned Options object.
*/
public function noConflict( $reInitialize = false ) {
$class = clone $this;
$class->isClone = true;
if ( $reInitialize ) {
$class->init();
}
return $class;
}
/**
* Get original instance. Since this could be a cloned object, let's get the original instance.
*
* @since 4.1.4
*
* @return self
*/
public function getOriginalInstance() {
if ( ! $this->isClone ) {
return $this;
}
$class = new \ReflectionClass( get_called_class() );
$optionName = aioseo()->helpers->toCamelCase( $class->getShortName() );
if ( isset( aioseo()->{ $optionName } ) ) {
return aioseo()->{ $optionName };
}
return $this;
}
}