_key_value_hash (key_value_hash), UNIQUE KEY ndx_aioseo_crawl_cleanup_blocked_args_regex (regex) ) {$charsetCollate};" ); } } /** * Adds a notification for the query arg monitor. * * @since 4.5.8 * * @return void */ private function addQueryArgMonitorNotification() { $options = $this->getRawOptions(); if ( empty( $options['searchAppearance']['advanced']['crawlCleanup']['enable'] ) || empty( $options['searchAppearance']['advanced']['crawlCleanup']['removeUnrecognizedQueryArgs'] ) ) { return; } $notification = Models\Notification::getNotificationByName( 'crawl-cleanup-updated' ); if ( $notification->exists() ) { return; } Models\Notification::addNotification( [ 'slug' => uniqid(), 'notification_name' => 'crawl-cleanup-updated', 'title' => __( 'Crawl Cleanup changes you should know about', 'all-in-one-seo-pack' ), 'content' => __( 'We\'ve made some significant changes to how we monitor Query Args for our Crawl Cleanup feature. Instead of DISABLING all query args and requiring you to add individual exceptions, we\'ve now changed it to ALLOW all query args by default with the option to easily block unrecognized ones through our new log table.', 'all-in-one-seo-pack' ), // phpcs:ignore Generic.Files.LineLength.MaxExceeded 'type' => 'info', 'level' => [ 'all' ], 'button1_label' => __( 'Learn More', 'all-in-one-seo-pack' ), 'button1_action' => 'http://route#aioseo-search-appearance&aioseo-scroll=aioseo-query-arg-monitoring&aioseo-highlight=aioseo-query-arg-monitoring:advanced', 'start' => gmdate( 'Y-m-d H:i:s' ) ] ); } /** * Deprecates the "No Pagination for Canonical URLs" setting. * * @since 4.5.9 * * @return void */ public function deprecateNoPaginationForCanonicalUrlsSetting() { $options = $this->getRawOptions(); if ( empty( $options['searchAppearance']['advanced']['noPaginationForCanonical'] ) ) { return; } $deprecatedOptions = aioseo()->internalOptions->deprecatedOptions; if ( ! in_array( 'noPaginationForCanonical', $deprecatedOptions, true ) ) { $deprecatedOptions[] = 'noPaginationForCanonical'; aioseo()->internalOptions->deprecatedOptions = $deprecatedOptions; } aioseo()->options->deprecated->searchAppearance->advanced->noPaginationForCanonical = true; } /** * Deprecates the "Breadcrumbs enabled" setting. * * @since 4.6.5 * * @return void */ public function deprecateBreadcrumbsEnabledSetting() { $options = $this->getRawOptions(); if ( ! isset( $options['breadcrumbs']['enable'] ) || 1 === intval( $options['breadcrumbs']['enable'] ) ) { return; } $deprecatedOptions = aioseo()->internalOptions->deprecatedOptions; if ( ! in_array( 'breadcrumbsEnable', $deprecatedOptions, true ) ) { $deprecatedOptions[] = 'breadcrumbsEnable'; aioseo()->internalOptions->deprecatedOptions = $deprecatedOptions; } aioseo()->options->deprecated->breadcrumbs->enable = false; } /** * Add tables for Writing Assistant. * * @since 4.7.4 * * @return void */ private function addWritingAssistantTables() { $db = aioseo()->core->db->db; $charsetCollate = ''; if ( ! empty( $db->charset ) ) { $charsetCollate .= "DEFAULT CHARACTER SET {$db->charset}"; } if ( ! empty( $db->collate ) ) { $charsetCollate .= " COLLATE {$db->collate}"; } if ( ! aioseo()->core->db->tableExists( 'aioseo_writing_assistant_posts' ) ) { $tableName = $db->prefix . 'aioseo_writing_assistant_posts'; aioseo()->core->db->execute( "CREATE TABLE {$tableName} ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `post_id` bigint(20) unsigned DEFAULT NULL, `keyword_id` bigint(20) unsigned DEFAULT NULL, `content_analysis_hash` VARCHAR(40) DEFAULT NULL, `content_analysis` text DEFAULT NULL, `created` datetime NOT NULL, `updated` datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY ndx_aioseo_writing_assistant_posts_post_id (post_id), KEY ndx_aioseo_writing_assistant_posts_keyword_id (keyword_id) ) {$charsetCollate};" ); } if ( ! aioseo()->core->db->tableExists( 'aioseo_writing_assistant_keywords' ) ) { $tableName = $db->prefix . 'aioseo_writing_assistant_keywords'; aioseo()->core->db->execute( "CREATE TABLE {$tableName} ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `uuid` varchar(40) NOT NULL, `keyword` varchar(255) NOT NULL, `country` varchar(10) NOT NULL DEFAULT 'us', `language` varchar(10) NOT NULL DEFAULT 'en', `progress` tinyint(3) DEFAULT 0, `keywords` mediumtext NULL, `competitors` mediumtext NULL, `created` datetime NOT NULL, `updated` datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY ndx_aioseo_writing_assistant_keywords_uuid (uuid), KEY ndx_aioseo_writing_assistant_keywords_keyword (keyword) ) {$charsetCollate};" ); } } /** * Cancels all outstanding sitemap ping actions. * This is needed because we've removed the Ping class. * * @since 4.7.5 * * @return void */ private function cancelScheduledSitemapPings() { as_unschedule_all_actions( 'aioseo_sitemap_ping' ); as_unschedule_all_actions( 'aioseo_sitemap_ping_recurring' ); } /** * Disable email reports. * * @since 4.7.7 * * @return void */ private function disableEmailReports() { aioseo()->options->advanced->emailSummary->enable = false; // Schedule a notification to remind the user to enable email reports in 2 weeks. aioseo()->actionScheduler->scheduleSingle( 'aioseo_email_reports_enable_reminder', 2 * WEEK_IN_SECONDS ); } /** * Cancels all occurrences of the report summary task. * This is needed in order to force the scheduled date to be reset. * * @since 4.7.9 * * @return void */ private function rescheduleEmailReport() { as_unschedule_all_actions( aioseo()->emailReports->summary->actionHook ); } /** * Fixes headlines that could not be analyzed. * * @since 4.7.9 * * @return void */ private function fixSavedHeadlines() { $headlines = aioseo()->internalOptions->internal->headlineAnalysis->headlines; if ( empty( $headlines ) ) { return; } foreach ( $headlines as $key => $headline ) { if ( ! json_decode( $headline ) ) { unset( $headlines[ $key ] ); } } aioseo()->internalOptions->internal->headlineAnalysis->headlines = $headlines; } /** * Resets the image scan date in order to force a new scan. * This is needed because we're now storing relative URLs in order to support site migrations. * * @since 4.8.3 * * @return void */ private function resetImageScanDate() { aioseo()->core->db->update( 'aioseo_posts' ) ->set( [ 'image_scan_date' => null ] ) ->run(); } /** * Adds our custom table for the SeoAnalysis/SeoAnalyzer homepage and competitor results. * * @since 4.8.3 * * @return void */ private function addSeoAnalyzerResultsTable() { $db = aioseo()->core->db->db; $charsetCollate = ''; if ( ! empty( $db->charset ) ) { $charsetCollate .= "DEFAULT CHARACTER SET {$db->charset}"; } if ( ! empty( $db->collate ) ) { $charsetCollate .= " COLLATE {$db->collate}"; } // Check for seo analyzer results table. if ( ! aioseo()->core->db->tableExists( 'aioseo_seo_analyzer_results' ) ) { $tableName = $db->prefix . 'aioseo_seo_analyzer_results'; aioseo()->core->db->execute( "CREATE TABLE {$tableName} ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `data` text NOT NULL, `score` varchar(255), `competitor_url` varchar(255), `created` datetime NOT NULL, `updated` datetime NOT NULL, PRIMARY KEY (id), KEY ndx_aioseo_seo_analyzer_results_competitor_url (competitor_url) ) {$charsetCollate};" ); // Reset the cache for the installed tables. aioseo()->internalOptions->database->installedTables = ''; } } /** * Migrate the SeoAnalyzer homepage results from the Internal Optinos to the new table. * * @since 4.8.3 * * @return void */ private function migrateSeoAnalyzerResults() { $internalOptions = $this->getRawInternalOptions(); $results = ! empty( $internalOptions['internal']['siteAnalysis']['results'] ) ? $internalOptions['internal']['siteAnalysis']['results'] : []; if ( empty( $results ) ) { return; } $parsedData = [ 'results' => is_string( $results ) ? json_decode( $results, true ) : $results, 'score' => $internalOptions['internal']['siteAnalysis']['score'], ]; Models\SeoAnalyzerResult::addResults( $parsedData ); aioseo()->core->cache->delete( 'analyze_site_code' ); aioseo()->core->cache->delete( 'analyze_site_body' ); } /** * Migrate the SeoAnalyzer competitors results from the Internal Optinos to the new table. * * @since 4.8.3 * * @return void */ private function migrateSeoAnalyzerCompetitors() { $internalOptions = $this->getRawInternalOptions(); $competitors = ! empty( $internalOptions['internal']['siteAnalysis']['competitors'] ) ? $internalOptions['internal']['siteAnalysis']['competitors'] : []; if ( empty( $competitors ) ) { return; } foreach ( $competitors as $url => $competitor ) { $parsedData = is_string( $competitor ) ? json_decode( $competitor, true ) : $competitor; $results = empty( $parsedData['results'] ) ? [] : $parsedData['results']; if ( empty( $results ) ) { continue; } Models\SeoAnalyzerResult::addResults( [ 'results' => $results, 'score' => $parsedData['score'], ], $url ); } aioseo()->core->cache->delete( 'analyze_site_code' ); aioseo()->core->cache->delete( 'analyze_site_body' ); } /** * Adds the AI column to our posts table. * * @since 4.8.4 * * @return void */ public function addAiColumn() { if ( ! aioseo()->core->db->columnExists( 'aioseo_posts', 'ai' ) ) { $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts'; if ( aioseo()->core->db->columnExists( 'aioseo_posts', 'open_ai' ) ) { aioseo()->core->db->execute( "ALTER TABLE {$tableName} ADD ai longtext DEFAULT NULL AFTER open_ai" ); } else { aioseo()->core->db->execute( "ALTER TABLE {$tableName} ADD ai longtext DEFAULT NULL AFTER options" ); } } } /** * Returns the raw options from the database. * * @since 4.8.3 * * @return array */ private function getRawInternalOptions() { // Options from the DB. $internalOptions = json_decode( get_option( aioseo()->internalOptions->optionsName ), true ); if ( empty( $internalOptions ) ) { $internalOptions = []; } return $internalOptions; } /** * Adds the column index for the cornerstone content table. * * @since 4.8.7 * * @return void */ private function addColumnIndexForCornerstoneContent() { if ( ! aioseo()->core->db->columnExists( 'aioseo_posts', 'pillar_content' ) || aioseo()->core->db->indexExists( 'aioseo_posts', 'ndx_aioseo_posts_pillar_content' ) ) { return; } $tableName = aioseo()->core->db->db->prefix . 'aioseo_posts'; aioseo()->core->db->execute( "ALTER TABLE {$tableName} ADD INDEX ndx_aioseo_posts_pillar_content (pillar_content)" ); } }