Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2023-0585: Updates.php in all-in-one-seo-pack/tags/4.2.9/app/Common/Main – WordPress Plugin Repository

The All in One SEO Pack plugin for WordPress is vulnerable to Stored Cross-Site Scripting via multiple parameters in versions up to, and including, 4.2.9 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers with Administrator role or above to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVE
#xss#web#ios#mac#google#js#wordpress#php#auth

1<?php2namespace AIOSEO\Plugin\Common\Main;34use \AIOSEO\Plugin\Common\Models;56// Exit if accessed directly.7if ( ! defined( ‘ABSPATH’ ) ) {8 exit;9}1011/**12 * Updater class.13 *14 * @since 4.0.015 */16class Updates {17 /**18 * Class constructor.19 *20 * @since 4.0.021 */22 public function __construct() {23 add_action( 'aioseo_v4_migrate_post_schema’, [ $this, ‘migratePostSchema’ ] );24 add_action( 'aioseo_v4_migrate_post_schema_default’, [ $this, ‘migratePostSchemaDefault’ ] );2526 if ( wp_doing_ajax() || wp_doing_cron() ) {27 return;28 }2930 add_action( 'init’, [ $this, ‘init’ ], 1001 );31 add_action( 'init’, [ $this, ‘runUpdates’ ], 1002 );32 add_action( 'init’, [ $this, ‘updateLatestVersion’ ], 3000 );33 }3435 /**36 * Sets the latest active version if it is not set yet.37 *38 * @since 4.0.039 *40 * @return void41 */42 public function init() {43 if ( ‘0.0’ !== aioseo()->internalOptions->internal->lastActiveVersion ) {44 return;45 }4647 // It’s possible the user may not have capabilities. Let’s add them now.48 aioseo()->access->addCapabilities();4950 $oldOptions = get_option( ‘aioseop_options’ );51 if ( ! empty( $oldOptions[‘last_active_version’] ) ) {52 aioseo()->internalOptions->internal->lastActiveVersion = $oldOptions[‘last_active_version’];53 }5455 $this->addInitialCustomTablesForV4();56 add_action( 'wp_loaded’, [ $this, ‘setDefaultSocialImages’ ], 1001 );57 }5859 /**60 * Runs our migrations.61 *62 * @since 4.0.063 *64 * @return void65 */66 public function runUpdates() {67 // The dynamic options have not yet fully loaded, so let’s refresh here to force that to happen.68 aioseo()->dynamicOptions->refresh(); // TODO: Check if we still need this since it already runs on 999 in the main AIOSEO file.6970 $lastActiveVersion = aioseo()->internalOptions->internal->lastActiveVersion;71 if ( version_compare( $lastActiveVersion, '4.0.5’, ‘<’ ) ) {72 $this->addImageScanDateColumn();73 }7475 if ( version_compare( $lastActiveVersion, '4.0.6’, ‘<’ ) ) {76 $this->disableTwitterUseOgDefault();77 $this->updateMaxImagePreviewDefault();78 }7980 if ( ! aioseo()->pro && version_compare( $lastActiveVersion, '4.0.6’, ‘=’ ) && ‘posts’ !== get_option( ‘show_on_front’ ) ) {81 aioseo()->migration->helpers->redoMigration();82 }8384 if ( version_compare( $lastActiveVersion, '4.0.13’, ‘<’ ) ) {85 $this->removeDuplicateRecords();86 }8788 if ( version_compare( $lastActiveVersion, '4.0.17’, ‘<’ ) ) {89 $this->removeLocationColumn();90 }9192 if ( version_compare( $lastActiveVersion, '4.1.2’, ‘<’ ) ) {93 $this->clearProductImages();94 }9596 if ( version_compare( $lastActiveVersion, '4.1.3’, ‘<’ ) ) {97 $this->addNotificationsNewColumn();98 $this->noindexWooCommercePages();99 $this->accessControlNewCapabilities();100 }101102 if ( version_compare( $lastActiveVersion, '4.1.3.3’, ‘<’ ) ) {103 $this->accessControlNewCapabilities();104 }105106 if ( version_compare( $lastActiveVersion, '4.1.4.3’, ‘<’ ) ) {107 $this->migrateDynamicSettings();108 }109110 if ( version_compare( $lastActiveVersion, '4.1.5’, ‘<’ ) ) {111 aioseo()->actionScheduler->unschedule( ‘aioseo_cleanup_action_scheduler’ );112 // Schedule routine to remove our old transients from the options table.113 aioseo()->actionScheduler->scheduleSingle( aioseo()->core->cachePrune->getOptionCacheCleanAction(), MINUTE_IN_SECONDS );114115 // Refresh with new Redirects capability.116 $this->accessControlNewCapabilities();117118 // Regenerate the sitemap if using a static one to update the data for the new stylesheets.119 aioseo()->sitemap->regenerateStaticSitemap();120121 $this->fixSchemaTypeDefault();122 }123124 if ( version_compare( $lastActiveVersion, '4.1.6’, ‘<’ ) ) {125 // Remove the recurring scheduled action for notifications.126 aioseo()->actionScheduler->unschedule( ‘aioseo_admin_notifications_update’ );127128 $this->migrateOgTwitterImageColumns();129130 // Set the OG data to false for current installs.131 aioseo()->options->social->twitter->general->useOgData = false;132 }133134 if ( version_compare( $lastActiveVersion, '4.1.8’, ‘<’ ) ) {135 $this->addLimitModifiedDateColumn();136137 // Refresh with new Redirects Page capability.138 $this->accessControlNewCapabilities();139 }140141 if ( version_compare( $lastActiveVersion, '4.1.9’, ‘<’ ) ) {142 $this->fixTaxonomyTags();143 $this->removeRevisionRecords();144 }145146 if ( version_compare( $lastActiveVersion, '4.0.0’, ‘>=’ ) && version_compare( $lastActiveVersion, '4.2.0’, ‘<’ ) ) {147 $this->migrateDeprecatedRunShortcodesSetting();148 }149150 if ( version_compare( $lastActiveVersion, '4.2.1’, ‘<’ ) ) {151 // Force WordPress to flush the rewrite rules.152 aioseo()->options->flushRewriteRules();153154 Models\Notification::deleteNotificationByName( ‘deprecated-filters’ );155 Models\Notification::deleteNotificationByName( ‘deprecated-filters-v2’ );156 }157158 if ( version_compare( $lastActiveVersion, '4.2.2’, ‘<’ ) ) {159 aioseo()->internalOptions->database->installedTables = '’;160161 $this->addOptionsColumn();162 $this->removeTabsColumn();163 $this->migrateUserContactMethods();164165 // Unschedule any static sitemap regeneration actions to remove any that failed and are still in-progress as a result.166 aioseo()->actionScheduler->unschedule( ‘aioseo_static_sitemap_regeneration’ );167 }168169 if ( version_compare( $lastActiveVersion, '4.2.4’, ‘<’ ) ) {170 $this->migrateContactTypes();171 $this->addNotificationsAddonColumn();172 }173174 if ( version_compare( $lastActiveVersion, '4.2.5’, ‘<’ ) ) {175 $this->addSchemaColumn();176 $this->schedulePostSchemaMigration();177 }178179 if ( version_compare( $lastActiveVersion, '4.2.4.2’, ‘>’ ) && version_compare( $lastActiveVersion, '4.2.6’, ‘<’ ) ) {180 // The default graphs only need to be remigrated if the user was on 4.2.5 or 4.2.5.1.181 $this->schedulePostSchemaDefaultMigration();182 }183184 if ( version_compare( $lastActiveVersion, '4.2.8’, ‘<’ ) ) {185 $this->migrateDashboardWidgetsOptions();186 }187188 do_action( 'aioseo_run_updates’, $lastActiveVersion );189190 // Always clear the cache if the last active version is different from our current.191 if ( version_compare( $lastActiveVersion, AIOSEO_VERSION, ‘<’ ) ) {192 aioseo()->core->cache->clear();193 }194 }195196 /**197 * Retrieve the raw options from the database for migration.198 *199 * @since 4.1.4200 *201 * @return array An array of options.202 */203 private function getRawOptions() {204 // Options from the DB.205 $commonOptions = json_decode( get_option( aioseo()->options->optionsName ), true );206 if ( empty( $commonOptions ) ) {207 $commonOptions = [];208 }209210 return $commonOptions;211 }212213 /**214 * Updates the latest version after all migrations and updates have run.215 *216 * @since 4.0.3217 *218 * @return void219 */220 public function updateLatestVersion() {221 if ( aioseo()->internalOptions->internal->lastActiveVersion === aioseo()->version ) {222 return;223 }224225 aioseo()->internalOptions->internal->lastActiveVersion = aioseo()->version;226227 // Bust the tableExists and columnExists cache.228 aioseo()->internalOptions->database->installedTables = '’;229230 // Bust the DB cache so we can make sure that everything is fresh.231 aioseo()->core->db->bustCache();232 }233234 /**235 * Adds our custom tables for V4.236 *237 * @since 4.0.0238 *239 * @return void240 */241 public function addInitialCustomTablesForV4() {242 $db = aioseo()->core->db->db;243 $charsetCollate = '’;244245 if ( ! empty( $db->charset ) ) {246 $charsetCollate .= "DEFAULT CHARACTER SET {$db->charset}";247 }248 if ( ! empty( $db->collate ) ) {249 $charsetCollate .= " COLLATE {$db->collate}";250 }251252 // Check for notifications table.253 if ( ! aioseo()->core->db->tableExists( ‘aioseo_notifications’ ) ) {254 $tableName = $db->prefix . 'aioseo_notifications’;255256 aioseo()->core->db->execute(257 "CREATE TABLE {$tableName} (258 id bigint(20) unsigned NOT NULL AUTO_INCREMENT,259 slug varchar(13) NOT NULL,260 title text NOT NULL,261 content longtext NOT NULL,262 type varchar(64) NOT NULL,263 level text NOT NULL,264 notification_id bigint(20) unsigned DEFAULT NULL,265 notification_name varchar(255) DEFAULT NULL,266 start datetime DEFAULT NULL,267 end datetime DEFAULT NULL,268 button1_label varchar(255) DEFAULT NULL,269 button1_action varchar(255) DEFAULT NULL,270 button2_label varchar(255) DEFAULT NULL,271 button2_action varchar(255) DEFAULT NULL,272 dismissed tinyint(1) NOT NULL DEFAULT 0,273 created datetime NOT NULL,274 updated datetime NOT NULL,275 PRIMARY KEY (id),276 UNIQUE KEY ndx_aioseo_notifications_slug (slug),277 KEY ndx_aioseo_notifications_dates (start, end),278 KEY ndx_aioseo_notifications_type (type),279 KEY ndx_aioseo_notifications_dismissed (dismissed)280 ) {$charsetCollate};"281 );282 }283284 if ( ! aioseo()->core->db->tableExists( ‘aioseo_posts’ ) ) {285 $tableName = $db->prefix . 'aioseo_posts’;286287 // Incorrect defaults are adjusted below through migrations.288 aioseo()->core->db->execute(289 "CREATE TABLE {$tableName} (290 id bigint(20) unsigned NOT NULL AUTO_INCREMENT,291 post_id bigint(20) unsigned NOT NULL,292 title text DEFAULT NULL,293 description text DEFAULT NULL,294 keywords mediumtext DEFAULT NULL,295 keyphrases longtext DEFAULT NULL,296 page_analysis longtext DEFAULT NULL,297 canonical_url text DEFAULT NULL,298 og_title text DEFAULT NULL,299 og_description text DEFAULT NULL,300 og_object_type varchar(64) DEFAULT 'default’,301 og_image_type varchar(64) DEFAULT 'default’,302 og_image_custom_url text DEFAULT NULL,303 og_image_custom_fields text DEFAULT NULL,304 og_custom_image_width int(11) DEFAULT NULL,305 og_custom_image_height int(11) DEFAULT NULL,306 og_video varchar(255) DEFAULT NULL,307 og_custom_url text DEFAULT NULL,308 og_article_section text DEFAULT NULL,309 og_article_tags text DEFAULT NULL,310 twitter_use_og tinyint(1) DEFAULT 1,311 twitter_card varchar(64) DEFAULT 'default’,312 twitter_image_type varchar(64) DEFAULT 'default’,313 twitter_image_custom_url text DEFAULT NULL,314 twitter_image_custom_fields text DEFAULT NULL,315 twitter_title text DEFAULT NULL,316 twitter_description text DEFAULT NULL,317 seo_score int(11) DEFAULT 0 NOT NULL,318 schema_type varchar(20) DEFAULT NULL,319 schema_type_options longtext DEFAULT NULL,320 pillar_content tinyint(1) DEFAULT NULL,321 robots_default tinyint(1) DEFAULT 1 NOT NULL,322 robots_noindex tinyint(1) DEFAULT 0 NOT NULL,323 robots_noarchive tinyint(1) DEFAULT 0 NOT NULL,324 robots_nosnippet tinyint(1) DEFAULT 0 NOT NULL,325 robots_nofollow tinyint(1) DEFAULT 0 NOT NULL,326 robots_noimageindex tinyint(1) DEFAULT 0 NOT NULL,327 robots_noodp tinyint(1) DEFAULT 0 NOT NULL,328 robots_notranslate tinyint(1) DEFAULT 0 NOT NULL,329 robots_max_snippet int(11) DEFAULT NULL,330 robots_max_videopreview int(11) DEFAULT NULL,331 robots_max_imagepreview varchar(20) DEFAULT 'none’,332 tabs mediumtext DEFAULT NULL,333 images longtext DEFAULT NULL,334 priority tinytext DEFAULT NULL,335 frequency tinytext DEFAULT NULL,336 videos longtext DEFAULT NULL,337 video_thumbnail text DEFAULT NULL,338 video_scan_date datetime DEFAULT NULL,339 local_seo longtext DEFAULT NULL,340 created datetime NOT NULL,341 updated datetime NOT NULL,342 PRIMARY KEY (id),343 KEY ndx_aioseo_posts_post_id (post_id)344 ) {$charsetCollate};"345 );346 }347348 // Reset the cache for the installed tables.349 aioseo()->internalOptions->database->installedTables = '’;350 }351352 /**353 * Sets the default social images.354 *355 * @since 4.0.0356 *357 * @return void358 */359 public function setDefaultSocialImages() {360 $siteLogo = aioseo()->helpers->getSiteLogoUrl();361 if ( $siteLogo && ! aioseo()->internalOptions->internal->migratedVersion ) {362 if ( ! aioseo()->options->social->facebook->general->defaultImagePosts ) {363 aioseo()->options->social->facebook->general->defaultImagePosts = $siteLogo;364 }365 if ( ! aioseo()->options->social->twitter->general->defaultImagePosts ) {366 aioseo()->options->social->twitter->general->defaultImagePosts = $siteLogo;367 }368 }369 }370371 /**372 * Adds the image scan date column to our posts table.373 *374 * @since 4.0.5375 *376 * @return void377 */378 public function addImageScanDateColumn() {379 if ( ! aioseo()->core->db->columnExists( 'aioseo_posts’, ‘image_scan_date’ ) ) {380 $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts’;381 aioseo()->core->db->execute(382 "ALTER TABLE {$tableName}383 ADD image_scan_date datetime DEFAULT NULL AFTER images"384 );385386 // Reset the cache for the installed tables.387 aioseo()->internalOptions->database->installedTables = '’;388 }389 }390391 /**392 * Modifes the default value of the twitter_use_og column.393 *394 * @since 4.0.6395 *396 * @return void397 */398 protected function disableTwitterUseOgDefault() {399 if ( aioseo()->core->db->tableExists( ‘aioseo_posts’ ) ) {400 $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts’;401 aioseo()->core->db->execute(402 "ALTER TABLE {$tableName}403 MODIFY twitter_use_og tinyint(1) DEFAULT 0"404 );405 }406 }407408 /**409 * Modifes the default value of the robots_max_imagepreview column.410 *411 * @since 4.0.6412 *413 * @return void414 */415 protected function updateMaxImagePreviewDefault() {416 if ( aioseo()->core->db->tableExists( ‘aioseo_posts’ ) ) {417 $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts’;418 aioseo()->core->db->execute(419 "ALTER TABLE {$tableName}420 MODIFY robots_max_imagepreview varchar(20) DEFAULT 'large’"421 );422 }423 }424425 /**426 * Deletes duplicate records in our custom tables.427 *428 * @since 4.0.13429 *430 * @return void431 */432 public function removeDuplicateRecords() {433 $duplicates = aioseo()->core->db->start( ‘aioseo_posts’ )434 ->select( ‘post_id, min(id) as id’ )435 ->groupBy( ‘post_id having count(post_id) > 1’ )436 ->orderBy( ‘count(post_id) DESC’ )437 ->run()438 ->result();439440 if ( empty( $duplicates ) ) {441 return;442 }443444 foreach ( $duplicates as $duplicate ) {445 $postId = $duplicate->post_id;446 $firstRecordId = $duplicate->id;447448 aioseo()->core->db->delete( ‘aioseo_posts’ )449 ->whereRaw( "( id > $firstRecordId AND post_id = $postId )" )450 ->run();451 }452 }453454 /**455 * Removes the location column.456 *457 * @since 4.0.17458 *459 * @return void460 */461 public function removeLocationColumn() {462 if ( aioseo()->core->db->columnExists( 'aioseo_posts’, ‘location’ ) ) {463 $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts’;464 aioseo()->core->db->execute(465 "ALTER TABLE {$tableName}466 DROP location"467 );468 }469 }470471 /**472 * Clears the image data for WooCommerce Products so that we scan them again and include product gallery images.473 *474 * @since 4.1.2475 *476 * @return void477 */478 public function clearProductImages() {479 if ( ! aioseo()->helpers->isWooCommerceActive() ) {480 return;481 }482483 aioseo()->core->db->update( ‘aioseo_posts as ap’ )484 ->join( 'posts as p’, ‘ap.post_id = p.ID’ )485 ->where( 'p.post_type’, ‘product’ )486 ->set(487 [488 ‘images’ => null,489 ‘image_scan_date’ => null490 ]491 )492 ->run();493 }494495 /**496 * Adds the new flag to the notifications table.497 *498 * @since 4.1.3499 *500 * @return void501 */502 public function addNotificationsNewColumn() {503 if ( ! aioseo()->core->db->columnExists( 'aioseo_notifications’, ‘new’ ) ) {504 $tableName = aioseo()->core->db->db->prefix . 'aioseo_notifications’;505 aioseo()->core->db->execute(506 "ALTER TABLE {$tableName}507 ADD new tinyint(1) NOT NULL DEFAULT 1 AFTER dismissed"508 );509510 // Reset the cache for the installed tables.511 aioseo()->internalOptions->database->installedTables = '’;512513 aioseo()->core->db514 ->update( ‘aioseo_notifications’ )515 ->where( 'new’, 1 )516 ->set( 'new’, 0 )517 ->run();518 }519 }520521 /**522 * Noindexes the WooCommerce cart, checkout and account pages.523 *524 * @since 4.1.3525 *526 * @return void527 */528 public function noindexWooCommercePages() {529 if ( ! aioseo()->helpers->isWooCommerceActive() ) {530 return;531 }532533 $cartId = (int) get_option( ‘woocommerce_cart_page_id’ );534 $checkoutId = (int) get_option( ‘woocommerce_checkout_page_id’ );535 $accountId = (int) get_option( ‘woocommerce_myaccount_page_id’ );536537 $cartPage = Models\Post::getPost( $cartId );538 $checkoutPage = Models\Post::getPost( $checkoutId );539 $accountPage = Models\Post::getPost( $accountId );540541 $newMeta = [542 ‘robots_default’ => false,543 ‘robots_noindex’ => true544 ];545546 if ( $cartPage->exists() ) {547 $cartPage->set( $newMeta );548 $cartPage->save();549 }550 if ( $checkoutPage->exists() ) {551 $checkoutPage->set( $newMeta );552 $checkoutPage->save();553 }554 if ( $accountPage->exists() ) {555 $accountPage->set( $newMeta );556 $accountPage->save();557 }558 }559560 /**561 * Adds the new capabilities for all the roles.562 *563 * @since 4.1.3564 *565 * @return void566 */567 protected function accessControlNewCapabilities() {568 aioseo()->access->addCapabilities();569 }570571 /**572 * Migrate dynamic settings to a separate options structure.573 *574 * @since 4.1.4575 *576 * @return void577 */578 protected function migrateDynamicSettings() {579 $rawOptions = $this->getRawOptions();580 $options = aioseo()->dynamicOptions->noConflict();581582 // Sitemap post type priorities/frequencies.583 if (584 ! empty( $rawOptions[‘sitemap’][‘dynamic’][‘priority’][‘postTypes’] )585 ) {586 foreach ( $rawOptions[‘sitemap’][‘dynamic’][‘priority’][‘postTypes’] as $postTypeName => $data ) {587 if ( $options->sitemap->priority->postTypes->has( $postTypeName ) ) {588 $options->sitemap->priority->postTypes->$postTypeName->priority = $data[‘priority’];589 $options->sitemap->priority->postTypes->$postTypeName->frequency = $data[‘frequency’];590 }591 }592 }593594 // Sitemap taxonomy priorities/frequencies.595 if (596 ! empty( $rawOptions[‘sitemap’][‘dynamic’][‘priority’][‘taxonomies’] )597 ) {598 foreach ( $rawOptions[‘sitemap’][‘dynamic’][‘priority’][‘taxonomies’] as $taxonomyName => $data ) {599 if ( $options->sitemap->priority->taxonomies->has( $taxonomyName ) ) {600 $options->sitemap->priority->taxonomies->$taxonomyName->priority = $data[‘priority’];601 $options->sitemap->priority->taxonomies->$taxonomyName->frequency = $data[‘frequency’];602 }603 }604 }605606 // Facebook post type object types.607 if (608 ! empty( $rawOptions[‘social’][‘facebook’][‘general’][‘dynamic’][‘postTypes’] )609 ) {610 foreach ( $rawOptions[‘social’][‘facebook’][‘general’][‘dynamic’][‘postTypes’] as $postTypeName => $data ) {611 if ( $options->social->facebook->general->postTypes->has( $postTypeName ) ) {612 $options->social->facebook->general->postTypes->$postTypeName->objectType = $data[‘objectType’];613 }614 }615 }616617 // Search appearance post type data.618 if (619 ! empty( $rawOptions[‘searchAppearance’][‘dynamic’][‘postTypes’] )620 ) {621 foreach ( $rawOptions[‘searchAppearance’][‘dynamic’][‘postTypes’] as $postTypeName => $data ) {622 if ( $options->searchAppearance->postTypes->has( $postTypeName ) ) {623 $options->searchAppearance->postTypes->$postTypeName->show = $data[‘show’];624 $options->searchAppearance->postTypes->$postTypeName->title = $data[‘title’];625 $options->searchAppearance->postTypes->$postTypeName->metaDescription = $data[‘metaDescription’];626 $options->searchAppearance->postTypes->$postTypeName->schemaType = $data[‘schemaType’];627 $options->searchAppearance->postTypes->$postTypeName->webPageType = $data[‘webPageType’];628 $options->searchAppearance->postTypes->$postTypeName->articleType = $data[‘articleType’];629 $options->searchAppearance->postTypes->$postTypeName->customFields = $data[‘customFields’];630631 // Advanced settings.632 $advanced = ! empty( $data[‘advanced’][‘robotsMeta’] ) ? $data[‘advanced’][‘robotsMeta’] : null;633 if ( ! empty( $advanced ) ) {634 $options->searchAppearance->postTypes->$postTypeName->advanced->robotsMeta->default = $data[‘advanced’][‘robotsMeta’][‘default’];635 $options->searchAppearance->postTypes->$postTypeName->advanced->robotsMeta->noindex = $data[‘advanced’][‘robotsMeta’][‘noindex’];636 $options->searchAppearance->postTypes->$postTypeName->advanced->robotsMeta->nofollow = $data[‘advanced’][‘robotsMeta’][‘nofollow’];637 $options->searchAppearance->postTypes->$postTypeName->advanced->robotsMeta->noarchive = $data[‘advanced’][‘robotsMeta’][‘noarchive’];638 $options->searchAppearance->postTypes->$postTypeName->advanced->robotsMeta->noimageindex = $data[‘advanced’][‘robotsMeta’][‘noimageindex’];639 $options->searchAppearance->postTypes->$postTypeName->advanced->robotsMeta->notranslate = $data[‘advanced’][‘robotsMeta’][‘notranslate’];640 $options->searchAppearance->postTypes->$postTypeName->advanced->robotsMeta->nosnippet = $data[‘advanced’][‘robotsMeta’][‘nosnippet’];641 $options->searchAppearance->postTypes->$postTypeName->advanced->robotsMeta->noodp = $data[‘advanced’][‘robotsMeta’][‘noodp’];642 $options->searchAppearance->postTypes->$postTypeName->advanced->robotsMeta->maxSnippet = $data[‘advanced’][‘robotsMeta’][‘maxSnippet’];643 $options->searchAppearance->postTypes->$postTypeName->advanced->robotsMeta->maxVideoPreview = $data[‘advanced’][‘robotsMeta’][‘maxVideoPreview’];644 $options->searchAppearance->postTypes->$postTypeName->advanced->robotsMeta->maxImagePreview = $data[‘advanced’][‘robotsMeta’][‘maxImagePreview’];645 $options->searchAppearance->postTypes->$postTypeName->advanced->showDateInGooglePreview = $data[‘advanced’][‘showDateInGooglePreview’];646 $options->searchAppearance->postTypes->$postTypeName->advanced->showPostThumbnailInSearch = $data[‘advanced’][‘showPostThumbnailInSearch’];647 $options->searchAppearance->postTypes->$postTypeName->advanced->showMetaBox = $data[‘advanced’][‘showMetaBox’];648 $options->searchAppearance->postTypes->$postTypeName->advanced->bulkEditing = $data[‘advanced’][‘bulkEditing’];649 }650651 if ( ‘attachment’ === $postTypeName ) {652 $options->searchAppearance->postTypes->$postTypeName->redirectAttachmentUrls = $data[‘redirectAttachmentUrls’];653 }654 }655 }656 }657658 // Search appearance taxonomy data.659 if (660 ! empty( $rawOptions[‘searchAppearance’][‘dynamic’][‘taxonomies’] )661 ) {662 foreach ( $rawOptions[‘searchAppearance’][‘dynamic’][‘taxonomies’] as $taxonomyName => $data ) {663 if ( $options->searchAppearance->taxonomies->has( $taxonomyName ) ) {664 $options->searchAppearance->taxonomies->$taxonomyName->show = $data[‘show’];665 $options->searchAppearance->taxonomies->$taxonomyName->title = $data[‘title’];666 $options->searchAppearance->taxonomies->$taxonomyName->metaDescription = $data[‘metaDescription’];667668 // Advanced settings.669 $advanced = ! empty( $data[‘advanced’][‘robotsMeta’] ) ? $data[‘advanced’][‘robotsMeta’] : null;670 if ( ! empty( $advanced ) ) {671 $options->searchAppearance->taxonomies->$taxonomyName->advanced->robotsMeta->default = $data[‘advanced’][‘robotsMeta’][‘default’];672 $options->searchAppearance->taxonomies->$taxonomyName->advanced->robotsMeta->noindex = $data[‘advanced’][‘robotsMeta’][‘noindex’];673 $options->searchAppearance->taxonomies->$taxonomyName->advanced->robotsMeta->nofollow = $data[‘advanced’][‘robotsMeta’][‘nofollow’];674 $options->searchAppearance->taxonomies->$taxonomyName->advanced->robotsMeta->noarchive = $data[‘advanced’][‘robotsMeta’][‘noarchive’];675 $options->searchAppearance->taxonomies->$taxonomyName->advanced->robotsMeta->noimageindex = $data[‘advanced’][‘robotsMeta’][‘noimageindex’];676 $options->searchAppearance->taxonomies->$taxonomyName->advanced->robotsMeta->notranslate = $data[‘advanced’][‘robotsMeta’][‘notranslate’];677 $options->searchAppearance->taxonomies->$taxonomyName->advanced->robotsMeta->nosnippet = $data[‘advanced’][‘robotsMeta’][‘nosnippet’];678 $options->searchAppearance->taxonomies->$taxonomyName->advanced->robotsMeta->noodp = $data[‘advanced’][‘robotsMeta’][‘noodp’];679 $options->searchAppearance->taxonomies->$taxonomyName->advanced->robotsMeta->maxSnippet = $data[‘advanced’][‘robotsMeta’][‘maxSnippet’];680 $options->searchAppearance->taxonomies->$taxonomyName->advanced->robotsMeta->maxVideoPreview = $data[‘advanced’][‘robotsMeta’][‘maxVideoPreview’];681 $options->searchAppearance->taxonomies->$taxonomyName->advanced->robotsMeta->maxImagePreview = $data[‘advanced’][‘robotsMeta’][‘maxImagePreview’];682 $options->searchAppearance->taxonomies->$taxonomyName->advanced->showDateInGooglePreview = $data[‘advanced’][‘showDateInGooglePreview’];683 $options->searchAppearance->taxonomies->$taxonomyName->advanced->showPostThumbnailInSearch = $data[‘advanced’][‘showPostThumbnailInSearch’];684 $options->searchAppearance->taxonomies->$taxonomyName->advanced->showMetaBox = $data[‘advanced’][‘showMetaBox’];685 }686 }687 }688 }689 }690691 /**692 * Fixes the default value for the post schema type.693 *694 * @since 4.1.5695 *696 * @return void697 */698 private function fixSchemaTypeDefault() {699 if ( aioseo()->core->db->tableExists( ‘aioseo_posts’ ) && aioseo()->core->db->columnExists( 'aioseo_posts’, ‘schema_type’ ) ) {700 $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts’;701 aioseo()->core->db->execute(702 "ALTER TABLE {$tableName}703 MODIFY schema_type varchar(20) DEFAULT 'default’"704 );705 }706 }707708 /**709 * Add in image with/height columns and image URL for caching.710 *711 * @since 4.1.6712 *713 * @return void714 */715 protected function migrateOgTwitterImageColumns() {716 if ( aioseo()->core->db->tableExists( ‘aioseo_posts’ ) ) {717 $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts’;718719 // OG Columns.720 if ( ! aioseo()->core->db->columnExists( 'aioseo_posts’, ‘og_image_url’ ) ) {721 aioseo()->core->db->execute(722 "ALTER TABLE {$tableName} ADD og_image_url text DEFAULT NULL AFTER og_image_type"723 );724 }725726 if ( aioseo()->core->db->columnExists( 'aioseo_posts’, ‘og_custom_image_height’ ) ) {727 aioseo()->core->db->execute(728 "ALTER TABLE {$tableName} CHANGE COLUMN og_custom_image_height og_image_height int(11) DEFAULT NULL AFTER og_image_url"729 );730 } elseif ( ! aioseo()->core->db->columnExists( 'aioseo_posts’, ‘og_image_height’ ) ) {731 aioseo()->core->db->execute(732 "ALTER TABLE {$tableName} ADD og_image_height int(11) DEFAULT NULL AFTER og_image_url"733 );734 }735736 if ( aioseo()->core->db->columnExists( 'aioseo_posts’, ‘og_custom_image_width’ ) ) {737 aioseo()->core->db->execute(738 "ALTER TABLE {$tableName} CHANGE COLUMN og_custom_image_width og_image_width int(11) DEFAULT NULL AFTER og_image_url"739 );740 } elseif ( ! aioseo()->core->db->columnExists( 'aioseo_posts’, ‘og_image_width’ ) ) {741 aioseo()->core->db->execute(742 "ALTER TABLE {$tableName} ADD og_image_width int(11) DEFAULT NULL AFTER og_image_url"743 );744 }745746 // Twitter image url columnn.747 if ( ! aioseo()->core->db->columnExists( 'aioseo_posts’, ‘twitter_image_url’ ) ) {748 aioseo()->core->db->execute(749 "ALTER TABLE {$tableName} ADD twitter_image_url text DEFAULT NULL AFTER twitter_image_type"750 );751 }752753 // Reset the cache for the installed tables.754 aioseo()->internalOptions->database->installedTables = '’;755 }756 }757758 /**759 * Adds the limit modified date column to our posts table.760 *761 * @since 4.1.8762 *763 * @return void764 */765 private function addLimitModifiedDateColumn() {766 if ( ! aioseo()->core->db->columnExists( 'aioseo_posts’, ‘limit_modified_date’ ) ) {767 $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts’;768 aioseo()->core->db->execute(769 "ALTER TABLE {$tableName}770 ADD limit_modified_date tinyint(1) NOT NULL DEFAULT 0 AFTER local_seo"771 );772773 // Reset the cache for the installed tables.774 aioseo()->internalOptions->database->installedTables = '’;775 }776 }777778 /**779 * Fixes tags that should not be in the search appearance taxonomy options.780 *781 * @since 4.1.9782 *783 * @return void784 */785 protected function fixTaxonomyTags() {786 $searchAppearanceTaxonomies = aioseo()->dynamicOptions->searchAppearance->taxonomies->all();787788 $replaces = [789 ‘#breadcrumb_separator’ => '#separator_sa’,790 ‘#breadcrumb_’ => '#’,791 ‘#blog_title’ => '#site_title’792 ];793794 foreach ( $searchAppearanceTaxonomies as $taxonomy => $searchAppearanceTaxonomy ) {795 aioseo()->dynamicOptions->searchAppearance->taxonomies->{$taxonomy}->title = str_replace(796 array_keys( $replaces ),797 array_values( $replaces ),798 $searchAppearanceTaxonomy[‘title’]799 );800801 aioseo()->dynamicOptions->searchAppearance->taxonomies->{$taxonomy}->metaDescription = str_replace(802 array_keys( $replaces ),803 array_values( $replaces ),804 $searchAppearanceTaxonomy[‘metaDescription’]805 );806 }807 }808809 /**810 * Removes any AIOSEO Post records for revisions.811 *812 * @since 4.1.9813 *814 * @return void815 */816 private function removeRevisionRecords() {817 $postsTableName = aioseo()->core->db->prefix . 'posts’;818 $aioseoPostsTableName = aioseo()->core->db->prefix . 'aioseo_posts’;819 aioseo()->core->db->execute(820 "DELETE FROM `$aioseoPostsTableName`821 WHERE `post_id` IN (822 SELECT `ID`823 FROM `$postsTableName`824 WHERE `post_parent` != 0825 AND `post_type` = 'revision’826 AND `post_status` = 'inherit’827 )"828 );829 }830831 /**832 * Enables the new shortcodes parsing setting if it was already enabled before as a deprecated setting.833 *834 * @since 4.2.0835 *836 * @return void837 */838 private function migrateDeprecatedRunShortcodesSetting() {839 if (840 in_array( 'runShortcodesInDescription’, aioseo()->internalOptions->deprecatedOptions, true ) &&841 ! aioseo()->options->deprecated->searchAppearance->advanced->runShortcodesInDescription842 ) {843 return;844 }845846 aioseo()->options->searchAppearance->advanced->runShortcodes = true;847 }848849 /**850 * Add options column.851 *852 * @since 4.2.2853 *854 * @return void855 */856 private function addOptionsColumn() {857 if ( ! aioseo()->core->db->columnExists( 'aioseo_posts’, ‘options’ ) ) {858 $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts’;859 aioseo()->core->db->execute(860 "ALTER TABLE {$tableName}861 ADD `options` longtext DEFAULT NULL AFTER `limit_modified_date`"862 );863864 // Reset the cache for the installed tables.865 aioseo()->internalOptions->database->installedTables = '’;866 }867 }868869 /**870 * Remove the tabs column as it is unnecessary.871 *872 * @since 4.2.2873 *874 * @return void875 */876 protected function removeTabsColumn() {877 if ( aioseo()->core->db->columnExists( 'aioseo_posts’, ‘tabs’ ) ) {878 $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts’;879 aioseo()->core->db->execute(880 "ALTER TABLE {$tableName}881 DROP tabs"882 );883 }884 }885886 /**887 * Migrates the user contact methods to the new format.888 *889 * @since 4.2.2890 *891 * @return void892 */893 private function migrateUserContactMethods() {894 $userMetaTableName = aioseo()->core->db->prefix . 'usermeta’;895896 aioseo()->core->db->execute(897 "UPDATE `$userMetaTableName`898 SET `meta_key` = 'aioseo_facebook_page_url’899 WHERE `meta_key` = 'aioseo_facebook’"900 );901902 aioseo()->core->db->execute(903 "UPDATE `$userMetaTableName`904 SET `meta_key` = 'aioseo_twitter_url’905 WHERE `meta_key` = 'aioseo_twitter’"906 );907 }908909 /**910 * Migrates some older values in the Knowledge Panel contact type setting that were removed.911 *912 * @since 4.2.4913 *914 * @return void915 */916 public function migrateContactTypes() {917 $oldValue = aioseo()->options->searchAppearance->global->schema->contactType;918 $oldValueLowerCase = strtolower( (string) $oldValue );919920 // Return if there is no value set or manual input is being used.921 if ( ! $oldValue || ‘manual’ === $oldValueLowerCase ) {922 return;923 }924925 switch ( $oldValueLowerCase ) {926 case 'billing support’:927 case 'customer support’:928 case 'reservations’:929 case 'sales’:930 case 'technical support’:931 // If we still support the value, do nothing.932 return;933 default:934 // Otherwise, migrate the existing value to the manual input field.935 if ( ‘bagage tracking’ === $oldValueLowerCase ) {936 // Let’s also fix this old typo.937 $oldValue = 'Baggage Tracking’;938 }939940 aioseo()->options->searchAppearance->global->schema->contactType = 'manual’;941 aioseo()->options->searchAppearance->global->schema->contactTypeManual = $oldValue;942 }943 }944945 /**946 * Add an addon column to the notifications table.947 *948 * @since 4.2.4949 *950 * @return void951 */952 private function addNotificationsAddonColumn() {953 if ( ! aioseo()->core->db->columnExists( 'aioseo_notifications’, ‘addon’ ) ) {954 $tableName = aioseo()->core->db->db->prefix . 'aioseo_notifications’;955 aioseo()->core->db->execute(956 "ALTER TABLE {$tableName}957 ADD `addon` varchar(64) DEFAULT NULL AFTER `slug`"958 );959960 // Reset the cache for the installed tables.961 aioseo()->internalOptions->database->installedTables = '’;962 }963 }964965 /**966 * Adds the schema column.967 *968 * @since 4.2.5969 *970 * @return void971 */972 private function addSchemaColumn() {973 if ( ! aioseo()->core->db->columnExists( 'aioseo_posts’, ‘schema’ ) ) {974 $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts’;975 aioseo()->core->db->execute(976 "ALTER TABLE {$tableName}977 ADD `schema` longtext DEFAULT NULL AFTER `seo_score`"978 );979 }980 }981982 /**983 * Schedules the post schema migration.984 *985 * @since 4.2.5986 *987 * @return void988 */989 private function schedulePostSchemaMigration() {990 aioseo()->actionScheduler->scheduleSingle( 'aioseo_v4_migrate_post_schema’, 10 );991 }992993 /**994 * Migrates then post schema to the new JSON column.995 *996 * @since 4.2.5997 *998 * @return void999 */1000 public function migratePostSchema() {1001 $posts = aioseo()->core->db->start( ‘aioseo_posts’ )1002 ->select( ‘*’ )1003 ->whereRaw( ‘`schema` IS NULL’ )1004 ->limit( 40 )1005 ->run()1006 ->models( ‘AIOSEO\\Plugin\\Common\\Models\\Post’ );10071008 if ( empty( $posts ) ) {1009 return;1010 }10111012 foreach ( $posts as $post ) {1013 $this->migratePostSchemaHelper( $post );1014 }10151016 // Once done, schedule the next action.1017 aioseo()->actionScheduler->scheduleSingle( 'aioseo_v4_migrate_post_schema’, 30 );1018 }10191020 /**1021 * Schedules the post schema migration to fix the default graphs.1022 *1023 * @since 4.2.61024 *1025 * @return void1026 */1027 private function schedulePostSchemaDefaultMigration() {1028 aioseo()->actionScheduler->scheduleSingle( 'aioseo_v4_migrate_post_schema_default’, 10 );10291030 if ( ! aioseo()->cache->get( ‘v4_migrate_post_schema_default_date’ ) ) {1031 aioseo()->cache->update( 'v4_migrate_post_schema_default_date’, gmdate( ‘Y-m-d H:i:s’ ), 3 * MONTH_IN_SECONDS );1032 }1033 }10341035 /**1036 * Updates the dashboardWidgets with the new array format.1037 *1038 * @since 4.2.81039 *1040 * @return void1041 */1042 private function migrateDashboardWidgetsOptions() {1043 $rawOptions = $this->getRawOptions();10441045 if ( empty( $rawOptions ) || ! is_bool( $rawOptions[‘advanced’][‘dashboardWidgets’] ) ) {1046 return;1047 }10481049 $widgets = [ ‘seoNews’ ];10501051 // If the dashboardWidgets was activated, let’s turn on the other widgets.1052 if ( $rawOptions[‘advanced’][‘dashboardWidgets’] ) {1053 $widgets[] = 'seoOverview’;1054 $widgets[] = 'seoSetup’;1055 }10561057 aioseo()->options->advanced->dashboardWidgets = $widgets;1058 }10591060 /**1061 * Migrates the post schema to the new JSON column again for posts using the default.1062 * This is needed to fix an oversight because in 4.2.5 we didn’t migrate any properties set to the default graph.1063 *1064 * @since 4.2.61065 *1066 * @return void1067 */1068 public function migratePostSchemaDefault() {1069 $migrationStartDate = aioseo()->cache->get( ‘v4_migrate_post_schema_default_date’ );1070 if ( ! $migrationStartDate ) {1071 return;1072 }10731074 $posts = aioseo()->core->db->start( ‘aioseo_posts’ )1075 ->select( ‘*’ )1076 ->where( 'schema_type =’, ‘default’ )1077 ->whereRaw( “updated < '$migrationStartDate’” )1078 ->limit( 40 )1079 ->run()1080 ->models( ‘AIOSEO\\Plugin\\Common\\Models\\Post’ );10811082 if ( empty( $posts ) ) {1083 aioseo()->cache->delete( ‘v4_migrate_post_schema_default_date’ );10841085 return;1086 }10871088 foreach ( $posts as $post ) {1089 $this->migratePostSchemaHelper( $post );1090 }10911092 // Once done, schedule the next action.1093 aioseo()->actionScheduler->scheduleSingle( 'aioseo_v4_migrate_post_schema_default’, 30 );1094 }10951096 /**1097 * Helper function for the schema migration.1098 *1099 * @since 4.2.51100 *1101 * @param Post $aioseoPost The AIOSEO post object.1102 * @return Post The modified AIOSEO post object.1103 */1104 public function migratePostSchemaHelper( $aioseoPost ) {1105 $post = aioseo()->helpers->getPost( $aioseoPost->post_id );1106 $schemaType = $aioseoPost->schema_type;1107 $schemaTypeOptions = json_decode( (string) $aioseoPost->schema_type_options );1108 $schemaOptions = Models\Post::getDefaultSchemaOptions( '’, $post );11091110 if ( empty( $schemaTypeOptions ) ) {1111 $aioseoPost->schema = $schemaOptions;1112 $aioseoPost->save();11131114 return $aioseoPost;1115 }11161117 // If the post is set to the default schema type, set the default for post type but then also get the properties.1118 $isDefault = ‘default’ === $schemaType;1119 if ( $isDefault ) {1120 $dynamicOptions = aioseo()->dynamicOptions->noConflict();1121 if ( ! empty( $post->post_type ) && $dynamicOptions->searchAppearance->postTypes->has( $post->post_type ) ) {1122 $schemaOptions->default->graphName = $dynamicOptions->searchAppearance->postTypes->{$post->post_type}->schemaType;1123 $schemaType = $dynamicOptions->searchAppearance->postTypes->{$post->post_type}->schemaType;1124 }1125 }11261127 $graph = [];1128 switch ( $schemaType ) {1129 case 'Article’:1130 $graph = [1131 ‘id’ => 'aioseo-article-' . uniqid(),1132 ‘slug’ => 'article’,1133 ‘graphName’ => 'Article’,1134 ‘label’ => __( 'Article’, ‘all-in-one-seo-pack’ ),1135 ‘properties’ => [1136 ‘type’ => ! empty( $schemaTypeOptions->article->articleType ) ? $schemaTypeOptions->article->articleType : 'Article’,1137 ‘name’ => '#post_title’,1138 ‘headline’ => '#post_title’,1139 ‘description’ => '#post_excerpt’,1140 ‘image’ => '’,1141 ‘keywords’ => '’,1142 ‘author’ => [1143 ‘name’ => '#author_name’,1144 ‘url’ => '#author_url’1145 ],1146 ‘dates’ => [1147 ‘include’ => true,1148 ‘datePublished’ => '’,1149 ‘dateModified’ => '’1150 ]1151 ]1152 ];1153 break;1154 case 'Course’:1155 $graph = [1156 ‘id’ => 'aioseo-course-' . uniqid(),1157 ‘slug’ => 'course’,1158 ‘graphName’ => 'Course’,1159 ‘label’ => __( 'Course’, ‘all-in-one-seo-pack’ ),1160 ‘properties’ => [1161 ‘name’ => ! empty( $schemaTypeOptions->course->name ) ? $schemaTypeOptions->course->name : '#post_title’,1162 ‘description’ => ! empty( $schemaTypeOptions->course->description ) ? $schemaTypeOptions->course->description : '#post_excerpt’,1163 ‘provider’ => [1164 ‘name’ => ! empty( $schemaTypeOptions->course->provider ) ? $schemaTypeOptions->course->provider : '’,1165 ‘url’ => '’,1166 ‘image’ => '’1167 ]1168 ]1169 ];1170 break;1171 case 'Product’:1172 $graph = [1173 ‘id’ => 'aioseo-product-' . uniqid(),1174 ‘slug’ => 'product’,1175 ‘graphName’ => 'Product’,1176 ‘label’ => __( 'Product’, ‘all-in-one-seo-pack’ ),1177 ‘properties’ => [1178 ‘autogenerate’ => true,1179 ‘name’ => '#post_title’,1180 ‘description’ => ! empty( $schemaTypeOptions->product->description ) ? $schemaTypeOptions->product->description : '#post_excerpt’,1181 ‘brand’ => ! empty( $schemaTypeOptions->product->brand ) ? $schemaTypeOptions->product->brand : '’,1182 ‘image’ => '’,1183 ‘identifiers’ => [1184 ‘sku’ => ! empty( $schemaTypeOptions->product->sku ) ? $schemaTypeOptions->product->sku : '’,1185 ‘gtin’ => '’,1186 ‘mpn’ => '’1187 ],1188 ‘offer’ => [1189 ‘price’ => ! empty( $schemaTypeOptions->product->price ) ? (float) $schemaTypeOptions->product->price : '’,1190 ‘currency’ => ! empty( $schemaTypeOptions->product->currency ) ? $schemaTypeOptions->product->currency : '’,1191 ‘availability’ => ! empty( $schemaTypeOptions->product->availability ) ? $schemaTypeOptions->product->availability : '’,1192 ‘validUntil’ => ! empty( $schemaTypeOptions->product->priceValidUntil ) ? $schemaTypeOptions->product->priceValidUntil : '’1193 ],1194 ‘rating’ => [1195 ‘minimum’ => 1,1196 ‘maximum’ => 51197 ],1198 ‘reviews’ => []1199 ]1200 ];12011202 $identifierType = ! empty( $schemaTypeOptions->product->identifierType ) ? $schemaTypeOptions->product->identifierType : '’;1203 if ( preg_match( '/gtin/i’, $identifierType ) ) {1204 $graph[‘properties’][‘identifiers’][‘gtin’] = $identifierType;1205 }12061207 if ( preg_match( '/mpn/i’, $identifierType ) ) {1208 $graph[‘properties’][‘identifiers’][‘mpn’] = $identifierType;1209 }12101211 $reviews = ! empty( $schemaTypeOptions->product->reviews ) ? $schemaTypeOptions->product->reviews : [];1212 if ( ! empty( $reviews ) ) {1213 foreach ( $reviews as $reviewData ) {1214 $reviewData = json_decode( $reviewData );1215 if ( empty( $reviewData ) ) {1216 continue;1217 }12181219 $graph[‘properties’][‘reviews’][] = [1220 ‘rating’ => $reviewData->rating,1221 ‘headline’ => $reviewData->headline,1222 ‘content’ => $reviewData->content,1223 ‘author’ => $reviewData->author1224 ];1225 }1226 }1227 break;1228 case 'Recipe’:1229 $graph = [1230 ‘id’ => 'aioseo-recipe-' . uniqid(),1231 ‘slug’ => 'recipe’,1232 ‘graphName’ => 'Recipe’,1233 ‘label’ => __( 'Recipe’, ‘all-in-one-seo-pack’ ),1234 ‘properties’ => [1235 ‘name’ => ! empty( $schemaTypeOptions->recipe->name ) ? $schemaTypeOptions->recipe->name : '#post_title’,1236 ‘description’ => ! empty( $schemaTypeOptions->recipe->description ) ? $schemaTypeOptions->recipe->description : '#post_excerpt’,1237 ‘author’ => ! empty( $schemaTypeOptions->recipe->author ) ? $schemaTypeOptions->recipe->author : '#author_name’,1238 ‘ingredients’ => ! empty( $schemaTypeOptions->recipe->ingredients ) ? $schemaTypeOptions->recipe->ingredients : '’,1239 ‘dishType’ => ! empty( $schemaTypeOptions->recipe->dishType ) ? $schemaTypeOptions->recipe->dishType : '’,1240 ‘cuisineType’ => ! empty( $schemaTypeOptions->recipe->cuisineType ) ? $schemaTypeOptions->recipe->cuisineType : '’,1241 ‘keywords’ => ! empty( $schemaTypeOptions->recipe->keywords ) ? $schemaTypeOptions->recipe->keywords : '’,1242 ‘image’ => ! empty( $schemaTypeOptions->recipe->image ) ? $schemaTypeOptions->recipe->image : '’,1243 ‘nutrition’ => [1244 ‘servings’ => ! empty( $schemaTypeOptions->recipe->servings ) ? $schemaTypeOptions->recipe->servings : '’,1245 ‘calories’ => ! empty( $schemaTypeOptions->recipe->calories ) ? $schemaTypeOptions->recipe->calories : '’1246 ],1247 ‘timeRequired’ => [1248 ‘preparation’ => ! empty( $schemaTypeOptions->recipe->preparationTime ) ? $schemaTypeOptions->recipe->preparationTime : '’,1249 ‘cooking’ => ! empty( $schemaTypeOptions->recipe->cookingTime ) ? $schemaTypeOptions->recipe->cookingTime : '’1250 ],1251 ‘instructions’ => []1252 ]1253 ];12541255 $instructions = ! empty( $schemaTypeOptions->recipe->instructions ) ? $schemaTypeOptions->recipe->instructions : [];1256 if ( ! empty( $instructions ) ) {1257 foreach ( $instructions as $instructionData ) {1258 $instructionData = json_decode( $instructionData );1259 if ( empty( $instructionData ) ) {1260 continue;1261 }12621263 $graph[‘properties’][‘instructions’][] = [1264 ‘name’ => '’,1265 ‘text’ => $instructionData->content,1266 ‘image’ => '’1267 ];1268 }1269 }1270 break;1271 case 'SoftwareApplication’:1272 $graph = [1273 ‘id’ => 'aioseo-software-application-' . uniqid(),1274 ‘slug’ => 'software-application’,1275 ‘graphName’ => 'SoftwareApplication’,1276 ‘label’ => __( 'Software’, ‘all-in-one-seo-pack’ ),1277 ‘properties’ => [1278 ‘name’ => ! empty( $schemaTypeOptions->software->name ) ? $schemaTypeOptions->software->name : '#post_title’,1279 ‘description’ => '#post_excerpt’,1280 ‘price’ => ! empty( $schemaTypeOptions->software->price ) ? (float) $schemaTypeOptions->software->price : '’,1281 ‘currency’ => ! empty( $schemaTypeOptions->software->currency ) ? $schemaTypeOptions->software->currency : '’,1282 ‘operatingSystem’ => ! empty( $schemaTypeOptions->software->operatingSystems ) ? $schemaTypeOptions->software->operatingSystems : '’,1283 ‘category’ => ! empty( $schemaTypeOptions->software->category ) ? $schemaTypeOptions->software->category : '’,1284 ‘rating’ => [1285 ‘value’ => '’,1286 ‘minimum’ => 1,1287 ‘maximum’ => 51288 ],1289 ‘review’ => [1290 ‘headline’ => '’,1291 ‘content’ => '’,1292 ‘author’ => '’1293 ]1294 ]1295 ];12961297 $reviews = ! empty( $schemaTypeOptions->software->reviews ) ? $schemaTypeOptions->software->reviews : [];1298 if ( ! empty( $reviews[0] ) ) {1299 $reviewData = json_decode( $reviews[0] );1300 if ( empty( $reviewData ) ) {1301 break;1302 }13031304 $graph[‘properties’][‘rating’][‘value’] = $reviewData->rating;1305 $graph[‘properties’][‘review’] = [1306 ‘headline’ => $reviewData->headline,1307 ‘content’ => $reviewData->content,1308 ‘author’ => $reviewData->author1309 ];1310 }1311 break;1312 case 'WebPage’:1313 if ( ‘FAQPage’ === $schemaTypeOptions->webPage->webPageType ) {1314 $graph = [1315 ‘id’ => 'aioseo-faq-page-' . uniqid(),1316 ‘slug’ => 'faq-page’,1317 ‘graphName’ => 'FAQPage’,1318 ‘label’ => __( 'FAQ Page’, ‘all-in-one-seo-pack’ ),1319 ‘properties’ => [1320 ‘type’ => $schemaTypeOptions->webPage->webPageType,1321 ‘name’ => '#post_title’,1322 ‘description’ => '#post_excerpt’,1323 ‘questions’ => []1324 ]1325 ];13261327 $faqs = $schemaTypeOptions->faq->pages;1328 if ( ! empty( $faqs ) ) {1329 foreach ( $faqs as $faqData ) {1330 $faqData = json_decode( $faqData );1331 if ( empty( $faqData ) ) {1332 continue;1333 }13341335 $graph[‘properties’][‘questions’][] = [1336 ‘question’ => $faqData->question,1337 ‘answer’ => $faqData->answer1338 ];1339 }1340 }1341 } else {1342 $graph = [1343 ‘id’ => 'aioseo-web-page-' . uniqid(),1344 ‘slug’ => 'web-page’,1345 ‘graphName’ => 'WebPage’,1346 ‘label’ => __( 'Web Page’, ‘all-in-one-seo-pack’ ),1347 ‘properties’ => [1348 ‘type’ => $schemaTypeOptions->webPage->webPageType,1349 ‘name’ => '’,1350 ‘description’ => '’1351 ]1352 ];1353 }1354 break;1355 case 'default’:1356 $dynamicOptions = aioseo()->dynamicOptions->noConflict();1357 if ( ! empty( $post->post_type ) && $dynamicOptions->searchAppearance->postTypes->has( $post->post_type ) ) {1358 $schemaOptions->defaultGraph = $dynamicOptions->searchAppearance->postTypes->{$post->post_type}->schemaType;1359 }1360 break;1361 case 'none’:1362 // If "none’, we simply don’t have to migrate anything.1363 default:1364 break;1365 }13661367 if ( ! empty( $graph ) ) {1368 if ( $isDefault ) {1369 $schemaOptions->default->data->{$schemaType} = $graph;1370 } else {1371 $schemaOptions->graphs[] = $graph;1372 $schemaOptions->default->isEnabled = false;1373 }1374 }13751376 $aioseoPost->schema = $schemaOptions;1377 $aioseoPost->save();13781379 return $aioseoPost;1380 }1381}

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907