true, 'exists' => $exists, 'path' => $path, 'url' => home_url('/robots.txt'), 'content' => $content, 'missing_rules' => $missing, 'is_valid' => count($missing) === 0, 'message' => count($missing) === 0 ? 'robots.txt contains the recommended WordPress SEO crawl and sitemap rules.' : 'robots.txt is missing one or more recommended crawl rules.', 'explanation' => 'These rules keep login, password reset, and admin URLs out of SEO crawl reports, and the Sitemap line tells crawlers where to find the preferred existing sitemap.', ]; } function ai_seo_cro_update_physical_robots_txt() { $path = ai_seo_cro_get_robots_txt_path(); $content = file_exists($path) && is_readable($path) ? (string) file_get_contents($path) : ''; $lines = preg_split('/\r\n|\r|\n/', $content); $lines = is_array($lines) ? $lines : []; $existing = array_map('trim', $lines); if (!preg_grep('/^User-agent:\s*\*$/i', $existing)) { if (count($lines) > 0 && trim((string) end($lines)) !== '') { $lines[] = ''; } $lines[] = 'User-agent: *'; $existing[] = 'User-agent: *'; } foreach (ai_seo_cro_get_required_robots_rules() as $rule) { if (!in_array($rule, $existing, true)) { $lines[] = $rule; $existing[] = $rule; } } foreach (ai_seo_cro_get_sitemap_robots_rules() as $sitemap_rule) { if (!ai_seo_cro_has_sitemap_robots_rule($existing, $sitemap_rule)) { $lines[] = $sitemap_rule; $existing[] = $sitemap_rule; } } $written = file_put_contents($path, trim(implode("\n", $lines)) . "\n"); if ($written === false) { return [ 'success' => false, 'message' => 'Unable to write robots.txt. Check file permissions for the WordPress root directory.', 'path' => $path, ]; } return ai_seo_cro_get_robots_txt_status(); } function ai_seo_cro_save_robots_txt_content($content) { $path = ai_seo_cro_get_robots_txt_path(); $content = str_replace(["\r\n", "\r"], "\n", (string) $content); $content = rtrim($content) . "\n"; if (file_exists($path) && !ai_seo_cro_path_is_writable($path)) { return [ 'success' => false, 'message' => 'robots.txt exists but is not writable. Update file permissions or edit it manually.', 'path' => $path, ]; } if (!file_exists($path) && !ai_seo_cro_path_is_writable(dirname($path))) { return [ 'success' => false, 'message' => 'The WordPress root directory is not writable, so robots.txt cannot be created.', 'path' => $path, ]; } $written = file_put_contents($path, $content); if ($written === false) { return [ 'success' => false, 'message' => 'Unable to write robots.txt. Check file permissions for the WordPress root directory.', 'path' => $path, ]; } return ai_seo_cro_get_robots_txt_status(); } function ai_seo_cro_noindex_author_archives($robots) { if (is_author()) { $robots['noindex'] = true; $robots['follow'] = true; } return $robots; } add_filter('wp_robots', 'ai_seo_cro_noindex_author_archives'); function ai_seo_cro_login_meta_robots() { echo "\n"; } add_action('login_head', 'ai_seo_cro_login_meta_robots', 1); function ai_seo_cro_get_seokey() { return sanitize_text_field((string) get_option('ai_seo_cro_seokey', '')); } function ai_seo_cro_update_seokey($key) { $key = sanitize_text_field(wp_unslash((string) $key)); if ($key === '') { delete_option('ai_seo_cro_seokey'); delete_option('ai_seo_cro_seokey_validation_status'); } else { update_option('ai_seo_cro_seokey', $key); } return $key; } function ai_seo_cro_get_seokey_validation_status() { $status = get_option('ai_seo_cro_seokey_validation_status', []); return is_array($status) ? $status : []; } function ai_seo_cro_update_seokey_validation_status($result) { $status = [ 'valid' => !empty($result['valid']), 'success' => !empty($result['success']), 'host' => sanitize_text_field((string) ($result['host'] ?? '')), 'message' => sanitize_text_field((string) ($result['message'] ?? '')), 'status_code' => isset($result['status_code']) ? (int) $result['status_code'] : 0, 'checked_at' => current_time('mysql'), ]; update_option('ai_seo_cro_seokey_validation_status', $status); return $status; } function ai_seo_cro_output_seokey_meta() { if (!(is_front_page() || is_home())) { return; } $key = ai_seo_cro_get_seokey(); if ($key === '') { return; } echo '\n"; } add_action('wp_head', 'ai_seo_cro_output_seokey_meta', 2); function ai_seo_cro_validate_seokey($key = '') { if (get_option('ai_seo_cro_seokey_service_enabled', '0') !== '1') { return [ 'success' => false, 'valid' => false, 'message' => 'Enable the 360 Digital Marketing SEO key validation service in 360 SEO > Site Audit before validating.', ]; } $key = trim((string) $key); if ($key === '') { $key = ai_seo_cro_get_seokey(); } if ($key === '') { $result = [ 'success' => false, 'valid' => false, 'key' => '', 'host' => (string) wp_parse_url(home_url('/'), PHP_URL_HOST), 'message' => 'Enter and save a Seokey before validating.', ]; $result['stored_status'] = ai_seo_cro_update_seokey_validation_status($result); return $result; } $host = esc_url_raw(home_url('/')); if ($host === '') { $result = [ 'success' => false, 'valid' => false, 'key' => $key, 'host' => '', 'message' => 'Unable to determine this site URL.', ]; $result['stored_status'] = ai_seo_cro_update_seokey_validation_status($result); return $result; } $url = add_query_arg( [ 'key' => $key, 'host' => $host, ], AI_SEO_CRO_Config::get('seokey_validate_url') ); $response = wp_safe_remote_get($url, [ 'timeout' => 20, 'redirection' => 3, 'headers' => [ 'Accept' => 'application/json', ], ]); if (is_wp_error($response)) { $result = [ 'success' => false, 'valid' => false, 'key' => $key, 'host' => $host, 'validate_url' => esc_url_raw($url), 'message' => $response->get_error_message(), ]; $result['stored_status'] = ai_seo_cro_update_seokey_validation_status($result); return $result; } $code = (int) wp_remote_retrieve_response_code($response); $body = (string) wp_remote_retrieve_body($response); $decoded = json_decode($body, true); $decoded = is_array($decoded) ? $decoded : []; $valid = false; if (isset($decoded['isValid'])) { $valid = (bool) $decoded['isValid']; } elseif (isset($decoded['valid'])) { $valid = (bool) $decoded['valid']; } elseif (isset($decoded['success'])) { $valid = (bool) $decoded['success']; } elseif (isset($decoded['status'])) { $valid = in_array(strtolower((string) $decoded['status']), ['valid', 'success', 'ok', 'active'], true); } else { $valid = $code >= 200 && $code < 300; } $result = [ 'success' => $code >= 200 && $code < 300, 'valid' => $valid, 'key' => $key, 'host' => $host, 'validate_url' => esc_url_raw($url), 'status_code' => $code, 'remote' => $decoded, 'message' => $decoded['message'] ?? ($valid ? 'Seokey validated successfully.' : 'Seokey validation failed.'), ]; $result['stored_status'] = ai_seo_cro_update_seokey_validation_status($result); return $result; } function ai_seo_cro_has_known_seo_plugin() { return defined('WPSEO_VERSION') || defined('RANK_MATH_VERSION') || defined('AIOSEO_VERSION') || class_exists('WPSEO_Frontend') || class_exists('RankMath') || class_exists('AIOSEO\\Plugin\\AIOSEO'); } function ai_seo_cro_is_canonical_fallback_enabled() { return get_option('ai_seo_cro_enable_canonical_fallback', '1') === '1'; } function ai_seo_cro_is_meta_description_fallback_enabled() { return get_option('ai_seo_cro_enable_meta_description_fallback', '1') === '1'; } function ai_seo_cro_is_og_description_fallback_enabled() { return get_option('ai_seo_cro_enable_og_description_fallback', '1') === '1'; } function ai_seo_cro_is_open_graph_fallback_enabled() { return get_option('ai_seo_cro_enable_open_graph_fallback', '1') === '1'; } function ai_seo_cro_is_og_image_fallback_enabled() { return get_option('ai_seo_cro_enable_og_image_fallback', '1') === '1'; } function ai_seo_cro_is_frontend_internal_nofollow_cleanup_enabled() { return get_option('ai_seo_cro_enable_frontend_internal_nofollow_cleanup', '1') === '1'; } function ai_seo_cro_is_image_alt_fallback_enabled() { return get_option('ai_seo_cro_enable_image_alt_fallback', '1') === '1'; } function ai_seo_cro_is_anchor_text_fallback_enabled() { return get_option('ai_seo_cro_enable_anchor_text_fallback', '1') === '1'; } function ai_seo_cro_is_heading_fallback_enabled() { return get_option('ai_seo_cro_enable_heading_fallback', '1') === '1'; } function ai_seo_cro_is_schema_fallback_enabled() { return get_option('ai_seo_cro_enable_schema_fallback', '1') === '1'; } function ai_seo_cro_is_force_https_enabled() { return get_option('ai_seo_cro_enable_force_https', '0') === '1'; } function ai_seo_cro_get_force_https_htaccess_path() { $wordpress_root = function_exists('get_home_path') ? get_home_path() : ABSPATH; return trailingslashit($wordpress_root) . '.htaccess'; } function ai_seo_cro_get_force_https_htaccess_rules() { return [ '', 'RewriteEngine On', '', '# Force HTTP to HTTPS', 'RewriteCond %{HTTPS} off', 'RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]', '', '', '', '# HSTS for HTTPS responses', 'Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"', '', ]; } function ai_seo_cro_get_force_https_htaccess_block() { return implode("\n", ai_seo_cro_get_force_https_htaccess_rules()); } function ai_seo_cro_get_force_https_htaccess_content() { $path = ai_seo_cro_get_force_https_htaccess_path(); if (!file_exists($path) || !is_readable($path)) { return ''; } return (string) file_get_contents($path); } function ai_seo_cro_has_force_https_htaccess_rules() { $content = ai_seo_cro_get_force_https_htaccess_content(); return (bool) preg_match( '#\s*RewriteEngine\s+On\s*\#\s*Force HTTP to HTTPS\s*RewriteCond\s+%\{HTTPS\}\s+off\s*RewriteRule\s+\^\(\.\*\)\$\s+https://%\{HTTP_HOST\}%\{REQUEST_URI\}\s+\[L,R=301\]\s*#i', $content ); } function ai_seo_cro_has_hsts_htaccess_rules() { $content = ai_seo_cro_get_force_https_htaccess_content(); return stripos($content, 'Strict-Transport-Security') !== false && stripos($content, 'max-age=31536000') !== false && stripos($content, 'includeSubDomains') !== false; } function ai_seo_cro_can_write_force_https_htaccess() { $path = ai_seo_cro_get_force_https_htaccess_path(); return file_exists($path) ? ai_seo_cro_path_is_writable($path) : ai_seo_cro_path_is_writable(dirname($path)); } function ai_seo_cro_update_force_https_htaccess($enabled = true) { $path = ai_seo_cro_get_force_https_htaccess_path(); $content = ai_seo_cro_get_force_https_htaccess_content(); if (!ai_seo_cro_can_write_force_https_htaccess()) { return [ 'success' => false, 'message' => 'Unable to write .htaccess. Check permissions for the WordPress root directory.', 'path' => $path, ]; } $legacy_marker = 'AI SEO CRO Force HTTPS'; $legacy_pattern = '/\R?# BEGIN ' . preg_quote($legacy_marker, '/') . '\b.*?# END ' . preg_quote($legacy_marker, '/') . '\b\R?/s'; $managed_pattern = '#\R?\s*RewriteEngine\s+On\s*\#\s*Force HTTP to HTTPS\s*RewriteCond\s+%\{HTTPS\}\s+off\s*RewriteRule\s+\^\(\.\*\)\$\s+https://%\{HTTP_HOST\}%\{REQUEST_URI\}\s+\[L,R=301\]\s*(?:\s*\s*\#\s*HSTS for HTTPS responses\s*Header\s+always\s+set\s+Strict-Transport-Security\s+"max-age=31536000;\s*includeSubDomains"\s*)?\R?#i'; $updated = (string) preg_replace($legacy_pattern, "\n", $content); $updated = (string) preg_replace($managed_pattern, "\n", $updated); if ($enabled) { $block = ai_seo_cro_get_force_https_htaccess_block() . "\n\n"; $wordpress_marker_position = strpos($updated, '# BEGIN WordPress'); if ($wordpress_marker_position === false) { $updated = $block . ltrim($updated); } else { $updated = substr($updated, 0, $wordpress_marker_position) . $block . substr($updated, $wordpress_marker_position); } } $updated = ltrim(preg_replace("/\n{3,}/", "\n\n", str_replace(["\r\n", "\r"], "\n", $updated))); $updated = rtrim($updated) . "\n"; if (file_put_contents($path, $updated, LOCK_EX) === false) { return [ 'success' => false, 'message' => $enabled ? 'Unable to add Force HTTPS rules to .htaccess.' : 'Unable to remove Force HTTPS rules from .htaccess.', 'path' => $path, ]; } return [ 'success' => true, 'message' => $enabled ? 'Force HTTPS rules added before the WordPress rules.' : 'Force HTTPS rules removed from .htaccess.', 'path' => $path, ]; } function ai_seo_cro_is_current_request_https() { $https = strtolower(sanitize_text_field(wp_unslash($_SERVER['HTTPS'] ?? ''))); $server_port = sanitize_text_field(wp_unslash($_SERVER['SERVER_PORT'] ?? '')); $forwarded_proto = strtolower(sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? ''))); $forwarded_ssl = strtolower(sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_SSL'] ?? ''))); $front_end_https = strtolower(sanitize_text_field(wp_unslash($_SERVER['HTTP_FRONT_END_HTTPS'] ?? ''))); $cf_visitor = strtolower((string) sanitize_text_field(wp_unslash($_SERVER['HTTP_CF_VISITOR'] ?? ''))); $forwarded_protocols = array_map('trim', explode(',', $forwarded_proto)); return is_ssl() || $https === 'on' || $https === '1' || $server_port === '443' || in_array('https', $forwarded_protocols, true) || $forwarded_ssl === 'on' || $front_end_https === 'on' || strpos($cf_visitor, '"scheme":"https"') !== false; } function ai_seo_cro_send_hsts_header() { if (headers_sent() || !ai_seo_cro_is_current_request_https()) { return; } header('Strict-Transport-Security: max-age=31536000; includeSubDomains'); } add_action('send_headers', 'ai_seo_cro_send_hsts_header'); function ai_seo_cro_should_force_https() { if ( is_admin() || wp_doing_ajax() || wp_doing_cron() || (defined('REST_REQUEST') && REST_REQUEST) || ai_seo_cro_is_current_request_https() || !ai_seo_cro_is_force_https_enabled() ) { return false; } $request_url = ai_seo_cro_get_current_request_url(); return $request_url !== '' && stripos($request_url, 'http://') === 0; } function ai_seo_cro_force_https_redirect() { if (!ai_seo_cro_should_force_https()) { return; } $request_url = ai_seo_cro_get_current_request_url(); $https_url = 'https://' . substr($request_url, 7); wp_safe_redirect(esc_url_raw($https_url), 301); exit; } add_action('template_redirect', 'ai_seo_cro_force_https_redirect', 0); function ai_seo_cro_get_current_request_url() { $scheme = ai_seo_cro_is_current_request_https() ? 'https' : 'http'; $host = sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'] ?? wp_parse_url(home_url('/'), PHP_URL_HOST))); $request_uri = sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'] ?? '/')); return esc_url_raw($scheme . '://' . $host . $request_uri); } function ai_seo_cro_get_current_canonical_url() { if (class_exists('AI_SEO_CRO_SEO_Manager')) { $managed = AI_SEO_CRO_SEO_Manager::current_canonical(); if ($managed !== '') return $managed; } if (is_singular()) { $canonical = wp_get_canonical_url(); return $canonical ? $canonical : get_permalink(); } if (is_front_page() || is_home()) { return home_url('/'); } if (is_category() || is_tag() || is_tax()) { $term = get_queried_object(); if ($term && !is_wp_error($term)) { return get_term_link($term); } } if (is_post_type_archive()) { $post_type = get_query_var('post_type'); if (is_array($post_type)) { $post_type = reset($post_type); } return get_post_type_archive_link($post_type); } if (is_date() || is_archive()) { return get_pagenum_link(max(1, (int) get_query_var('paged')), false); } return ''; } function ai_seo_cro_should_manage_frontend_seo_output() { if ( is_admin() || wp_doing_ajax() || is_feed() || (function_exists('is_robots') && is_robots()) || (function_exists('wp_is_json_request') && wp_is_json_request()) || (function_exists('is_sitemap') && is_sitemap()) ) { return false; } $request_url = ai_seo_cro_get_current_request_url(); if ($request_url && ai_seo_cro_is_seo_excluded_url($request_url)) { return false; } return true; } function ai_seo_cro_should_manage_canonical() { return ai_seo_cro_is_canonical_fallback_enabled() && ai_seo_cro_should_manage_frontend_seo_output(); } function ai_seo_cro_output_canonical() { if (!ai_seo_cro_should_manage_canonical() || ai_seo_cro_has_known_seo_plugin()) { return; } remove_action('wp_head', 'rel_canonical'); $canonical = ai_seo_cro_get_current_canonical_url(); if (!$canonical || is_wp_error($canonical)) { return; } echo '\n"; } add_action('wp_head', 'ai_seo_cro_output_canonical', 1); function ai_seo_cro_filter_missing_open_graph_image($image) { if (trim((string) $image) !== '') { return $image; } if (!ai_seo_cro_is_og_image_fallback_enabled() || !ai_seo_cro_should_manage_frontend_seo_output()) { return $image; } $fallback_image = ai_seo_cro_get_fallback_og_image_url(); return $fallback_image !== '' ? $fallback_image : $image; } add_filter('wpseo_opengraph_image', 'ai_seo_cro_filter_missing_open_graph_image', 20); add_filter('wpseo_twitter_image', 'ai_seo_cro_filter_missing_open_graph_image', 20); function ai_seo_cro_get_current_meta_description() { $text = class_exists('AI_SEO_CRO_SEO_Manager') ? AI_SEO_CRO_SEO_Manager::current_description() : ''; if ($text !== '') { return ai_seo_cro_normalize_meta_description($text); } elseif (is_singular()) { $post = get_queried_object(); if ($post instanceof WP_Post) { $text = has_excerpt($post) ? get_the_excerpt($post) : $post->post_content; } } elseif (is_front_page() || is_home()) { $text = trim(get_bloginfo('description')); if ($text === '') { $recent = get_posts([ 'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => 3, 'orderby' => 'date', 'order' => 'DESC', 'fields' => 'ids', 'no_found_rows' => true, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ]); $titles = array_filter(array_map('get_the_title', $recent)); $text = implode(', ', $titles); } } elseif (is_archive()) { $text = trim(wp_strip_all_tags(get_the_archive_title() . ' ' . get_the_archive_description())); } if ($text === '') { $text = get_bloginfo('name'); } return ai_seo_cro_normalize_meta_description($text); } function ai_seo_cro_get_current_heading_fallbacks() { if (is_singular()) { $title = trim(get_the_title()); return [ 'h1' => $title !== '' ? $title : wp_get_document_title(), 'h2' => $title !== '' ? 'About ' . $title : 'Page Overview', ]; } if (is_front_page() || is_home()) { $site_name = trim(get_bloginfo('name')); return [ 'h1' => $site_name !== '' ? $site_name : wp_get_document_title(), 'h2' => is_home() ? 'Latest Articles' : 'Featured Content', ]; } if (is_archive()) { $title = trim(wp_strip_all_tags(get_the_archive_title())); return [ 'h1' => $title !== '' ? $title : wp_get_document_title(), 'h2' => 'Archive Overview', ]; } $title = trim(wp_get_document_title()); return [ 'h1' => $title !== '' ? $title : get_bloginfo('name'), 'h2' => 'Page Overview', ]; } function ai_seo_cro_normalize_meta_description($text) { $text = preg_replace('/\s+/', ' ', wp_strip_all_tags(strip_shortcodes((string) $text))); $text = trim(html_entity_decode((string) $text, ENT_QUOTES, get_bloginfo('charset') ?: 'UTF-8')); $site_name = trim(get_bloginfo('name')); if ($text === '') { $text = $site_name; } if (mb_strlen($text) < 120) { $suffix = $site_name !== '' ? sprintf(' Explore helpful articles, updates, and resources from %s for readers looking for clear guidance and practical next steps.', $site_name) : ' Explore helpful articles, updates, and resources for readers looking for clear guidance and practical next steps.'; $text = trim($text . ' ' . $suffix); } if (mb_strlen($text) > 160) { $text = rtrim(mb_substr($text, 0, 157), " \t\n\r\0\x0B.,;:-") . '...'; } return $text; } function ai_seo_cro_prepare_template_enhancements() { if (!ai_seo_cro_should_manage_frontend_seo_output()) { return; } $canonical = ai_seo_cro_get_current_canonical_url(); $description = ai_seo_cro_get_current_meta_description(); $og_image = ai_seo_cro_get_fallback_og_image_url(); $og_tags = ai_seo_cro_get_current_open_graph_tags($canonical, $description, $og_image); if ( (!$canonical || is_wp_error($canonical) || !ai_seo_cro_is_canonical_fallback_enabled()) && (!ai_seo_cro_is_meta_description_fallback_enabled() || $description === '') && (!ai_seo_cro_is_open_graph_fallback_enabled() || empty($og_tags)) && (!ai_seo_cro_is_og_description_fallback_enabled() || $description === '') && (!ai_seo_cro_is_og_image_fallback_enabled() || $og_image === '') && !ai_seo_cro_is_frontend_internal_nofollow_cleanup_enabled() && !ai_seo_cro_is_image_alt_fallback_enabled() && !ai_seo_cro_is_anchor_text_fallback_enabled() && !ai_seo_cro_is_heading_fallback_enabled() && !ai_seo_cro_is_schema_fallback_enabled() && (!function_exists('ai_seo_cro_is_automatic_internal_link_repair_enabled') || !ai_seo_cro_is_automatic_internal_link_repair_enabled()) ) { return; } if ($canonical && !is_wp_error($canonical) && ai_seo_cro_is_canonical_fallback_enabled()) { $GLOBALS['ai_seo_cro_pending_canonical_url'] = $canonical; } if ($description !== '' && ai_seo_cro_is_meta_description_fallback_enabled()) { $GLOBALS['ai_seo_cro_pending_meta_description'] = $description; } if ($description !== '' && ai_seo_cro_is_og_description_fallback_enabled()) { $GLOBALS['ai_seo_cro_pending_og_description'] = $description; } if ($og_image !== '' && ai_seo_cro_is_og_image_fallback_enabled()) { $GLOBALS['ai_seo_cro_pending_og_image'] = $og_image; } if (!empty($og_tags) && ai_seo_cro_is_open_graph_fallback_enabled()) { $GLOBALS['ai_seo_cro_pending_open_graph_tags'] = $og_tags; } if (ai_seo_cro_is_heading_fallback_enabled()) { $GLOBALS['ai_seo_cro_pending_heading_fallbacks'] = ai_seo_cro_get_current_heading_fallbacks(); } if (ai_seo_cro_is_schema_fallback_enabled()) { $GLOBALS['ai_seo_cro_pending_schema'] = ai_seo_cro_get_current_schema_fallback(); } // WordPress owns and closes the template buffer (available since WP 6.9). // Older versions retain wp_head metadata without a plugin-owned buffer. add_filter('wp_template_enhancement_output_buffer', 'ai_seo_cro_inject_canonical_into_html'); } add_action('template_redirect', 'ai_seo_cro_prepare_template_enhancements', 1); function ai_seo_cro_inject_canonical_into_html($html) { $html = (string) $html; if ($html === '') { return $html; } if (ai_seo_cro_is_frontend_internal_nofollow_cleanup_enabled()) { $html = ai_seo_cro_strip_internal_nofollow_from_html($html); } if ( function_exists('ai_seo_cro_is_automatic_internal_link_repair_enabled') && ai_seo_cro_is_automatic_internal_link_repair_enabled() && function_exists('ai_seo_cro_repair_internal_links_in_content') ) { $link_repair = ai_seo_cro_repair_internal_links_in_content($html); $html = $link_repair['content']; } if (ai_seo_cro_is_image_alt_fallback_enabled()) { $html = ai_seo_cro_fill_empty_image_alt_in_html($html); } if (ai_seo_cro_is_anchor_text_fallback_enabled()) { $html = ai_seo_cro_fix_empty_anchor_links_in_html($html); } if (ai_seo_cro_is_heading_fallback_enabled()) { $html = ai_seo_cro_fill_missing_headings_in_html($html); } if (stripos($html, '') === false) { return $html; } $canonical = $GLOBALS['ai_seo_cro_pending_canonical_url'] ?? ''; if ($canonical && !is_wp_error($canonical) && !preg_match('/rel=["\']canonical["\']/i', $html)) { $tag = '\n"; $html = (string) preg_replace('/<\/head>/i', $tag . '', $html, 1); } $description = $GLOBALS['ai_seo_cro_pending_meta_description'] ?? ''; if ($description !== '') { $html = ai_seo_cro_inject_or_replace_meta_description($html, $description); } $og_description = $GLOBALS['ai_seo_cro_pending_og_description'] ?? ''; if ($og_description !== '') { $html = ai_seo_cro_inject_or_replace_og_description($html, $og_description); } $og_image = $GLOBALS['ai_seo_cro_pending_og_image'] ?? ''; if ($og_image !== '') { $html = ai_seo_cro_inject_or_replace_og_image($html, $og_image); } $open_graph_tags = $GLOBALS['ai_seo_cro_pending_open_graph_tags'] ?? []; if (!empty($open_graph_tags)) { $html = ai_seo_cro_inject_or_replace_open_graph_tags($html, $open_graph_tags); } $schema = $GLOBALS['ai_seo_cro_pending_schema'] ?? []; if (!empty($schema) && !ai_seo_cro_html_has_schema($html)) { $html = ai_seo_cro_inject_schema_into_html($html, $schema); } return $html; } function ai_seo_cro_get_current_open_graph_tags($canonical = '', $description = '', $image_url = '') { if (!$canonical || is_wp_error($canonical)) { $canonical = ai_seo_cro_get_current_canonical_url(); } if (!$canonical || is_wp_error($canonical)) { $canonical = ai_seo_cro_get_current_request_url(); } if ($description === '') { $description = ai_seo_cro_get_current_meta_description(); } if ($image_url === '') { $image_url = ai_seo_cro_get_fallback_og_image_url(); } $site_name = trim(get_bloginfo('name')); $title = trim(wp_get_document_title()); if (class_exists('AI_SEO_CRO_SEO_Manager')) { $social_title = AI_SEO_CRO_SEO_Manager::current_social_title(); $social_description = AI_SEO_CRO_SEO_Manager::current_social_description(); if ($social_title !== '') $title = $social_title; if ($social_description !== '') $description = $social_description; } if ($title === '' && is_singular()) { $title = trim(get_the_title()); } if ($title === '') { $title = $site_name; } $locale = str_replace('-', '_', (string) get_locale()); $type = is_singular('post') ? 'article' : 'website'; return array_filter([ 'og:title' => $title, 'og:type' => $type, 'og:url' => esc_url_raw((string) $canonical), 'og:site_name' => $site_name, 'og:description' => $description, 'og:image' => esc_url_raw((string) $image_url), 'og:locale' => $locale, ], function ($value) { return trim((string) $value) !== ''; }); } function ai_seo_cro_get_current_schema_fallback() { $url = ai_seo_cro_get_current_canonical_url(); if (!$url || is_wp_error($url)) { $url = ai_seo_cro_get_current_request_url(); } $site_name = trim(get_bloginfo('name')); $description = ai_seo_cro_get_current_meta_description(); $schema = [ '@context' => 'https://schema.org', '@type' => 'WebPage', 'name' => wp_get_document_title(), 'url' => $url, 'description' => $description, 'isPartOf' => [ '@type' => 'WebSite', 'name' => $site_name, 'url' => home_url('/'), ], ]; if (class_exists('AI_SEO_CRO_SEO_Manager')) { $managed_type = AI_SEO_CRO_SEO_Manager::schema_type(); if ($managed_type !== '') $schema['@type'] = $managed_type; } if (is_singular()) { $post = get_queried_object(); if ($post instanceof WP_Post) { $title = trim(get_the_title($post)); $managed_type = class_exists('AI_SEO_CRO_SEO_Manager') ? AI_SEO_CRO_SEO_Manager::schema_type() : ''; $schema['@type'] = $managed_type !== '' ? $managed_type : (get_post_type($post) === 'post' ? 'BlogPosting' : 'WebPage'); $schema['headline'] = $title !== '' ? $title : wp_get_document_title(); $schema['name'] = $schema['headline']; $schema['mainEntityOfPage'] = $url; $schema['datePublished'] = get_the_date('c', $post); $schema['dateModified'] = get_the_modified_date('c', $post); $author_id = (int) $post->post_author; $author_name = $author_id > 0 ? trim(get_the_author_meta('display_name', $author_id)) : ''; if ($author_name !== '') { $schema['author'] = [ '@type' => 'Person', 'name' => $author_name, ]; } if ($site_name !== '') { $schema['publisher'] = ai_seo_cro_get_schema_organization(); } } } elseif (is_front_page() || is_home()) { $schema['@type'] = 'WebSite'; $schema['name'] = $site_name !== '' ? $site_name : wp_get_document_title(); $schema['url'] = home_url('/'); unset($schema['isPartOf']); } elseif (is_archive()) { $archive_title = trim(wp_strip_all_tags(get_the_archive_title())); $schema['@type'] = 'CollectionPage'; $schema['name'] = $archive_title !== '' ? $archive_title : wp_get_document_title(); } return array_filter($schema, function ($value) { return $value !== '' && $value !== null && $value !== []; }); } function ai_seo_cro_get_fallback_og_image_url() { if (class_exists('AI_SEO_CRO_SEO_Manager')) { $social_image = AI_SEO_CRO_SEO_Manager::current_social_image(); if ($social_image !== '') return $social_image; } $default_image_id = (int) get_option('ai_seo_cro_default_og_image_id', 0); if ($default_image_id > 0) { $default_image_url = wp_get_attachment_image_url($default_image_id, 'full'); if ($default_image_url) { return esc_url_raw($default_image_url); } } $default_image_url = esc_url_raw((string) get_option('ai_seo_cro_default_og_image_url', '')); if ($default_image_url !== '') { return $default_image_url; } $logo_id = (int) get_theme_mod('custom_logo'); if ($logo_id <= 0) { return ''; } $logo_url = wp_get_attachment_image_url($logo_id, 'full'); if (!$logo_url) { return ''; } return esc_url_raw($logo_url); } function ai_seo_cro_get_default_og_image_status() { $image_id = (int) get_option('ai_seo_cro_default_og_image_id', 0); $image_url = esc_url_raw((string) get_option('ai_seo_cro_default_og_image_url', '')); $effective_url = ai_seo_cro_get_fallback_og_image_url(); return [ 'id' => $image_id, 'url' => $image_url, 'effective_url' => $effective_url, 'uses_site_logo' => $image_url === '' && $image_id <= 0 && $effective_url !== '', ]; } function ai_seo_cro_update_default_og_image($image_id = null, $image_url = null) { if ($image_id !== null) { $image_id = max(0, (int) $image_id); if ($image_id > 0 && get_post_type($image_id) === 'attachment') { update_option('ai_seo_cro_default_og_image_id', (string) $image_id); } else { delete_option('ai_seo_cro_default_og_image_id'); } } if ($image_url !== null) { $image_url = esc_url_raw(trim((string) $image_url)); if ($image_url !== '') { update_option('ai_seo_cro_default_og_image_url', $image_url); } else { delete_option('ai_seo_cro_default_og_image_url'); } } } function ai_seo_cro_get_schema_organization() { $setup = class_exists('AI_SEO_CRO_Setup_Wizard') ? AI_SEO_CRO_Setup_Wizard::data() : []; $organization = [ '@type' => ($setup['site_type'] ?? 'organization') === 'person' ? 'Person' : 'Organization', 'name' => $setup['site_name'] ?? get_bloginfo('name'), 'url' => home_url('/'), ]; if (!empty($setup['alternate_name'])) $organization['alternateName'] = $setup['alternate_name']; if (!empty($setup['social'])) $organization['sameAs'] = array_values($setup['social']); $logo_url = !empty($setup['logo_url']) ? esc_url_raw($setup['logo_url']) : ai_seo_cro_get_fallback_og_image_url(); if ($logo_url !== '') { $organization['logo'] = $logo_url; } return array_filter($organization); } function ai_seo_cro_html_has_schema($html) { return preg_match('/]*type=["\']application\/ld\+json["\'][^>]*>/i', (string) $html) || stripos((string) $html, 'schema.org') !== false; } function ai_seo_cro_inject_schema_into_html($html, $schema) { $json = wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); if (!$json) { return $html; } $tag = '\n"; return (string) preg_replace('/<\/head>/i', $tag . '', (string) $html, 1); } function ai_seo_cro_inject_or_replace_open_graph_tags($html, $tags) { foreach ((array) $tags as $property => $content) { $property = strtolower(trim((string) $property)); $content = trim((string) $content); if ($property === '' || $content === '') { continue; } $html = ai_seo_cro_inject_or_replace_meta_property($html, $property, $content); } return $html; } function ai_seo_cro_inject_or_replace_meta_property($html, $property, $content) { $property = esc_attr($property); $content = $property === 'og:image' ? esc_url($content) : esc_attr($content); if ($content === '') { return $html; } $tag = '\n"; $pattern = '/]*(?:property|name)=["\']' . preg_quote($property, '/') . '["\'][^>]*>/i'; if (!preg_match($pattern, $html, $match)) { return (string) preg_replace('/<\/head>/i', $tag . '', $html, 1); } $current = ''; if (preg_match('/content=["\']([^"\']*)["\']/i', $match[0], $content_match)) { $current = html_entity_decode($content_match[1], ENT_QUOTES, get_bloginfo('charset') ?: 'UTF-8'); } if (trim($current) !== '') { return $html; } return str_replace($match[0], $tag, $html); } function ai_seo_cro_inject_or_replace_meta_description($html, $description) { $description = esc_attr($description); $tag = '\n"; if (!preg_match('/]*name=["\']description["\'][^>]*>/i', $html, $match)) { return (string) preg_replace('/<\/head>/i', $tag . '', $html, 1); } $current = ''; if (preg_match('/content=["\']([^"\']*)["\']/i', $match[0], $content_match)) { $current = html_entity_decode($content_match[1], ENT_QUOTES, get_bloginfo('charset') ?: 'UTF-8'); } if (mb_strlen(trim($current)) >= 120) { return $html; } return str_replace($match[0], $tag, $html); } function ai_seo_cro_inject_or_replace_og_description($html, $description) { $description = esc_attr($description); $tag = '\n"; if (!preg_match('/]*(?:property|name)=["\']og:description["\'][^>]*>/i', $html, $match)) { return (string) preg_replace('/<\/head>/i', $tag . '', $html, 1); } $current = ''; if (preg_match('/content=["\']([^"\']*)["\']/i', $match[0], $content_match)) { $current = html_entity_decode($content_match[1], ENT_QUOTES, get_bloginfo('charset') ?: 'UTF-8'); } if (trim($current) !== '') { return $html; } return str_replace($match[0], $tag, $html); } function ai_seo_cro_inject_or_replace_og_image($html, $image_url) { $image_url = esc_url($image_url); if ($image_url === '') { return $html; } $tag = '\n"; if (!preg_match('/]*(?:property|name)=["\']og:image["\'][^>]*>/i', $html, $match)) { return (string) preg_replace('/<\/head>/i', $tag . '', $html, 1); } $current = ''; if (preg_match('/content=["\']([^"\']*)["\']/i', $match[0], $content_match)) { $current = html_entity_decode($content_match[1], ENT_QUOTES, get_bloginfo('charset') ?: 'UTF-8'); } if (trim($current) !== '') { return $html; } return str_replace($match[0], $tag, $html); } function ai_seo_cro_strip_internal_nofollow_from_html($html) { if (stripos($html, 'nofollow') === false) { return $html; } return (string) preg_replace_callback('/]*>/i', function ($matches) { $tag = $matches[0]; if (stripos($tag, 'nofollow') === false || !preg_match('/\srel=(["\'])(.*?)\1/i', $tag, $rel_match)) { return $tag; } $href = ''; if (preg_match('/\shref=(["\'])(.*?)\1/i', $tag, $href_match)) { $href = html_entity_decode($href_match[2], ENT_QUOTES, get_bloginfo('charset') ?: 'UTF-8'); } $is_internal = $href === '' || strpos($href, '#') === 0 || (function_exists('ai_seo_cro_is_internal_link_href') && ai_seo_cro_is_internal_link_href($href)); if (!$is_internal) { return $tag; } $tokens = preg_split('/\s+/', strtolower(trim($rel_match[2]))); $tokens = array_values(array_unique(array_filter((array) $tokens, function ($token) { return $token !== '' && $token !== 'nofollow'; }))); if (empty($tokens)) { return preg_replace('/\srel=(["\']).*?\1/i', '', $tag, 1); } return preg_replace('/\srel=(["\']).*?\1/i', ' rel="' . esc_attr(implode(' ', $tokens)) . '"', $tag, 1); }, $html); } function ai_seo_cro_fill_empty_image_alt_in_html($html) { if (stripos($html, ']*>/i', function ($matches) { $tag = $matches[0]; if (preg_match('/\salt=(["\'])(.*?)\1/i', $tag, $alt_match)) { $current_alt = trim(html_entity_decode($alt_match[2], ENT_QUOTES, get_bloginfo('charset') ?: 'UTF-8')); if ($current_alt !== '') { return $tag; } } $alt = ai_seo_cro_get_fallback_image_alt($tag); if ($alt === '') { return $tag; } if (preg_match('/\salt=(["\']).*?\1/i', $tag)) { return preg_replace('/\salt=(["\']).*?\1/i', ' alt="' . esc_attr($alt) . '"', $tag, 1); } if (preg_match('/\/\s*>$/', $tag)) { return preg_replace('/\s*\/\s*>$/', ' alt="' . esc_attr($alt) . '" />', $tag, 1); } return rtrim($tag, '>') . ' alt="' . esc_attr($alt) . '">'; }, $html); } function ai_seo_cro_get_fallback_image_alt($tag) { $attributes = []; foreach (['title', 'aria-label', 'src', 'class'] as $attribute) { if (preg_match('/\s' . preg_quote($attribute, '/') . '=(["\'])(.*?)\1/i', (string) $tag, $match)) { $attributes[$attribute] = trim(html_entity_decode($match[2], ENT_QUOTES, get_bloginfo('charset') ?: 'UTF-8')); } } foreach (['title', 'aria-label'] as $attribute) { if (!empty($attributes[$attribute])) { return $attributes[$attribute]; } } $src = $attributes['src'] ?? ''; $class = strtolower($attributes['class'] ?? ''); $src_host = strtolower((string) wp_parse_url($src, PHP_URL_HOST)); if (strpos($src_host, 'gravatar.com') !== false || strpos($class, 'avatar') !== false) { return 'Comment author avatar'; } $path = (string) wp_parse_url($src, PHP_URL_PATH); $filename = pathinfo($path, PATHINFO_FILENAME); $filename = trim(preg_replace('/[-_]+/', ' ', (string) $filename)); if ($filename !== '' && !preg_match('/^[a-f0-9]{16,}$/i', $filename)) { return ucwords($filename); } return 'Image'; } function ai_seo_cro_fix_empty_anchor_links_in_html($html) { $html = (string) $html; if ($html === '' || stripos($html, 'loadHTML($html_for_dom, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NONET); if (!$loaded) { libxml_clear_errors(); libxml_use_internal_errors($previous_errors); return $html; } foreach ($dom->childNodes as $node) { if ($node->nodeType === XML_PI_NODE) { $dom->removeChild($node); break; } } $site_host = ai_seo_cro_normalize_host((string) wp_parse_url(home_url('/'), PHP_URL_HOST)); $site_name = trim(get_bloginfo('name')) ?: 'website'; $links = $dom->getElementsByTagName('a'); foreach ($links as $link) { if (!$link instanceof DOMElement) { continue; } $href = trim($link->getAttribute('href')); if ($href === '') { continue; } $visible_text = trim((string) preg_replace('/\s+/u', ' ', $link->textContent)); $is_non_descriptive = ai_seo_cro_is_non_descriptive_anchor_text($visible_text); $existing_aria = trim($link->getAttribute('aria-label')); $existing_title = trim($link->getAttribute('title')); $target_label = ai_seo_cro_get_anchor_target_label($href, $link, $site_name); if ( $is_non_descriptive && $target_label === '' && ai_seo_cro_should_replace_empty_external_link($href, $link, $site_host) ) { $href = home_url('/'); $link->setAttribute('href', $href); $target_label = $site_name; } if (!$is_non_descriptive && $existing_aria !== '') { continue; } if ($target_label === '') { $target_label = $site_name; } $label = ai_seo_cro_generate_descriptive_anchor_label($visible_text, $target_label); if ($existing_aria === '') { $link->setAttribute('aria-label', $label); } if ($existing_title === '') { $link->setAttribute('title', $label); } if ($is_non_descriptive) { ai_seo_cro_append_screen_reader_anchor_context($dom, $link, $label); } } $updated_html = (string) $dom->saveHTML(); $updated_html = (string) preg_replace('/^<\?xml.*?\?>\s*/u', '', $updated_html); libxml_clear_errors(); libxml_use_internal_errors($previous_errors); return $updated_html !== '' ? $updated_html : $html; } function ai_seo_cro_is_non_descriptive_anchor_text($text) { $text = strtolower(trim((string) preg_replace('/\s+/u', ' ', wp_strip_all_tags((string) $text)))); if ($text === '') { return true; } if (!preg_match('/[\p{L}\p{N}]/u', $text)) { return true; } $generic = [ 'click here', 'here', 'read more', 'learn more', 'view more', 'more', 'details', 'view', 'visit', 'continue', 'continue reading', 'read article', 'read post', 'see more', 'find out more', 'explore more', 'get started', 'start now', 'check it out', 'this page', 'link', 'open', 'go', 'next', ]; return in_array($text, $generic, true); } function ai_seo_cro_get_anchor_target_label($href, $link, $site_name = 'website') { $image_alt = ai_seo_cro_get_first_image_alt_inside_link($link); if ($image_alt !== '') { return $image_alt; } if ($link instanceof DOMElement) { $existing_title = trim($link->getAttribute('title')); if ($existing_title !== '' && !ai_seo_cro_is_non_descriptive_anchor_text($existing_title)) { return $existing_title; } } $href = trim((string) $href); if ($href === '' || $href === '#') { return $site_name; } if (stripos($href, 'tel:') === 0) { return 'Call ' . trim(substr($href, 4)); } if (stripos($href, 'mailto:') === 0) { return 'Email ' . trim(substr($href, 7)); } $post_id = url_to_postid($href); if (!$post_id && strpos($href, '/') === 0) { $post_id = url_to_postid(home_url($href)); } if ($post_id) { $title = trim(wp_strip_all_tags(get_the_title($post_id))); if ($title !== '') { return $title; } } $parsed = wp_parse_url($href); if (empty($parsed)) { return $site_name; } if (!empty($parsed['path'])) { $path = trim($parsed['path'], '/'); if ($path !== '') { $parts = explode('/', $path); $last_part = (string) end($parts); $last_part = preg_replace('/\.[a-zA-Z0-9]+$/', '', $last_part); $last_part = trim(str_replace(['-', '_'], ' ', (string) $last_part)); if ($last_part !== '' && !preg_match('/^[a-f0-9]{16,}$/i', $last_part)) { return ucwords($last_part); } } } if (!empty($parsed['host'])) { return ai_seo_cro_normalize_host($parsed['host']); } return $site_name; } function ai_seo_cro_generate_descriptive_anchor_label($anchor_text, $target_label) { $text = strtolower(trim((string) preg_replace('/\s+/u', ' ', $anchor_text))); $target_label = trim((string) $target_label); if ($target_label === '') { $target_label = trim(get_bloginfo('name')) ?: 'website'; } if (in_array($text, ['read more', 'continue reading', 'read article', 'read post'], true)) { return 'Read more about ' . $target_label; } if (in_array($text, ['learn more', 'find out more', 'explore more'], true)) { return 'Learn more about ' . $target_label; } if (in_array($text, ['view more', 'view', 'see more'], true)) { return 'View ' . $target_label; } if ($text === 'details') { return 'View details about ' . $target_label; } if (in_array($text, ['get started', 'start now'], true)) { return 'Get started with ' . $target_label; } return 'Visit ' . $target_label; } function ai_seo_cro_append_screen_reader_anchor_context($dom, $link, $label) { if (!$dom instanceof DOMDocument || !$link instanceof DOMElement) { return; } foreach ($link->getElementsByTagName('span') as $span) { if ($span instanceof DOMElement && strpos($span->getAttribute('class'), '360-seo-anchor-context') !== false) { return; } } $span = $dom->createElement('span', ' ' . $label); $span->setAttribute('class', '360-seo-anchor-context'); $span->setAttribute('style', 'position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden;'); $link->appendChild($span); } function ai_seo_cro_has_meaningful_anchor_text($text) { $text = trim((string) $text); return $text !== '' && (bool) preg_match('/[\p{L}\p{N}]/u', $text); } function ai_seo_cro_get_first_image_alt_inside_link($link) { if (!$link instanceof DOMElement) { return ''; } $images = $link->getElementsByTagName('img'); foreach ($images as $image) { if (!$image instanceof DOMElement) { continue; } $alt = trim($image->getAttribute('alt')); if ($alt !== '') { return $alt; } } return ''; } function ai_seo_cro_should_replace_empty_external_link($href, $link, $site_host) { $href = trim((string) $href); if ($href === '' || $href === '#') { return false; } if ( stripos($href, 'tel:') === 0 || stripos($href, 'mailto:') === 0 || stripos($href, 'sms:') === 0 ) { return false; } $parsed = wp_parse_url($href); if (empty($parsed['host'])) { return false; } $link_host = ai_seo_cro_normalize_host($parsed['host']); if ($link_host === $site_host) { return false; } return !ai_seo_cro_is_safe_external_icon_link($href, $link_host, $link); } function ai_seo_cro_is_safe_external_icon_link($href, $host, $link) { $safe_hosts = [ 'facebook.com', 'instagram.com', 'linkedin.com', 'twitter.com', 'x.com', 'youtube.com', 'youtu.be', 'pinterest.com', 'whatsapp.com', 'wa.me', 't.me', 'telegram.me', ]; foreach ($safe_hosts as $safe_host) { if ($host === $safe_host || substr($host, -strlen('.' . $safe_host)) === '.' . $safe_host) { return true; } } $class = $link instanceof DOMElement ? strtolower($link->getAttribute('class')) : ''; $id = $link instanceof DOMElement ? strtolower($link->getAttribute('id')) : ''; $href = strtolower((string) $href); foreach (['facebook', 'instagram', 'linkedin', 'twitter', 'youtube', 'pinterest', 'whatsapp', 'telegram', 'social'] as $keyword) { if (strpos($class, $keyword) !== false || strpos($id, $keyword) !== false || strpos($href, $keyword) !== false) { return true; } } return false; } function ai_seo_cro_generate_anchor_label_from_url($href, $site_name = 'website') { return ai_seo_cro_generate_descriptive_anchor_label('', ai_seo_cro_get_anchor_target_label($href, null, $site_name)); } function ai_seo_cro_normalize_host($host) { $host = strtolower(trim((string) $host)); return preg_replace('/^www\./', '', $host); } function ai_seo_cro_fill_missing_headings_in_html($html) { if (stripos((string) $html, '' . esc_html($h1_text) . "\n"; $html = ai_seo_cro_insert_heading_fallback($html, $heading); $has_h1 = true; } if (!$has_h2 && $h2_text !== '') { $heading = '

' . esc_html($h2_text) . "

\n"; if ($has_h1 && preg_match('/<\/h1>/i', $html)) { $html = (string) preg_replace('/<\/h1>/i', '' . "\n" . $heading, $html, 1); } else { $html = ai_seo_cro_insert_heading_fallback($html, $heading); } } return $html; } function ai_seo_cro_html_has_non_empty_heading($html, $tag_name) { if (!preg_match_all('/<' . preg_quote($tag_name, '/') . '\b[^>]*>(.*?)<\/' . preg_quote($tag_name, '/') . '>/is', (string) $html, $matches)) { return false; } foreach ($matches[1] as $content) { $text = trim(preg_replace('/\s+/', ' ', wp_strip_all_tags($content))); if ($text !== '') { return true; } } return false; } function ai_seo_cro_insert_heading_fallback($html, $heading) { if (preg_match('/]*>/i', $html, $match, PREG_OFFSET_CAPTURE)) { $position = $match[0][1] + strlen($match[0][0]); return substr($html, 0, $position) . "\n" . $heading . substr($html, $position); } if (preg_match('/]*>/i', $html, $match, PREG_OFFSET_CAPTURE)) { $position = $match[0][1] + strlen($match[0][0]); return substr($html, 0, $position) . "\n" . $heading . substr($html, $position); } return $heading . $html; } function ai_seo_cro_get_theme_wp_head_status() { $paths = array_unique(array_filter([ trailingslashit(get_stylesheet_directory()) . 'header.php', trailingslashit(get_template_directory()) . 'header.php', ])); $files = []; foreach ($paths as $path) { $readable = is_readable($path); $content = $readable ? (string) file_get_contents($path) : ''; $files[] = [ 'path' => $path, 'readable' => $readable, 'has_wp_head' => $readable && stripos($content, 'wp_head') !== false, ]; } return [ 'has_wp_head' => count(array_filter($files, function ($file) { return !empty($file['has_wp_head']); })) > 0, 'files' => $files, ]; } function ai_seo_cro_get_canonical_fix_status() { $theme = ai_seo_cro_get_theme_wp_head_status(); $enabled = ai_seo_cro_is_canonical_fallback_enabled(); $has_seo_plugin = ai_seo_cro_has_known_seo_plugin(); return [ 'success' => true, 'enabled' => $enabled, 'meta_description_enabled' => ai_seo_cro_is_meta_description_fallback_enabled(), 'open_graph_enabled' => ai_seo_cro_is_open_graph_fallback_enabled(), 'og_description_enabled' => ai_seo_cro_is_og_description_fallback_enabled(), 'og_image_enabled' => ai_seo_cro_is_og_image_fallback_enabled(), 'default_og_image' => ai_seo_cro_get_default_og_image_status(), 'frontend_internal_nofollow_cleanup_enabled' => ai_seo_cro_is_frontend_internal_nofollow_cleanup_enabled(), 'image_alt_fallback_enabled' => ai_seo_cro_is_image_alt_fallback_enabled(), 'anchor_text_fallback_enabled' => ai_seo_cro_is_anchor_text_fallback_enabled(), 'heading_fallback_enabled' => ai_seo_cro_is_heading_fallback_enabled(), 'schema_fallback_enabled' => ai_seo_cro_is_schema_fallback_enabled(), 'has_known_seo_plugin' => $has_seo_plugin, 'theme_has_wp_head' => $theme['has_wp_head'], 'theme_files' => $theme['files'], 'homepage_url' => home_url('/'), 'homepage_canonical' => home_url('/'), 'output_method' => function_exists('wp_start_template_enhancement_output_buffer') ? 'wp_head plus WordPress-managed template enhancements' : 'wp_head (whole-page enhancements require WordPress 6.9 or later)', 'message' => $has_seo_plugin ? 'A known SEO plugin is active; fallback repair only changes final HTML when tags are missing or too short.' : ($enabled ? 'Meta, Open Graph, canonical, heading, image ALT, anchor text, nofollow, and schema fallbacks are enabled.' : 'Meta and canonical fallback is disabled.'), ]; } function ai_seo_cro_update_canonical_fix($enabled = true, $settings = []) { if (is_array($settings)) { $has_image_id = array_key_exists('default_og_image_id', $settings); $has_image_url = array_key_exists('default_og_image_url', $settings); if ($has_image_id || $has_image_url) { ai_seo_cro_update_default_og_image( $has_image_id ? $settings['default_og_image_id'] : null, $has_image_url ? $settings['default_og_image_url'] : null ); } } update_option('ai_seo_cro_enable_canonical_fallback', $enabled ? '1' : '0'); update_option('ai_seo_cro_enable_meta_description_fallback', $enabled ? '1' : '0'); update_option('ai_seo_cro_enable_og_description_fallback', $enabled ? '1' : '0'); update_option('ai_seo_cro_enable_og_image_fallback', $enabled ? '1' : '0'); update_option('ai_seo_cro_enable_frontend_internal_nofollow_cleanup', $enabled ? '1' : '0'); update_option('ai_seo_cro_enable_image_alt_fallback', $enabled ? '1' : '0'); update_option('ai_seo_cro_enable_anchor_text_fallback', $enabled ? '1' : '0'); update_option('ai_seo_cro_enable_heading_fallback', $enabled ? '1' : '0'); update_option('ai_seo_cro_enable_schema_fallback', $enabled ? '1' : '0'); $status = ai_seo_cro_get_canonical_fix_status(); $status['message'] = $enabled ? 'Meta, Open Graph, canonical, heading, image ALT, anchor text, schema, and internal nofollow fallbacks enabled. Run a new crawl after clearing cache.' : 'Meta, Open Graph, canonical, heading, image ALT, anchor text, schema, and internal nofollow fallbacks disabled.'; return $status; } function ai_seo_cro_get_force_https_status() { $home_url = home_url('/'); $https_url = preg_replace('#^http://#i', 'https://', $home_url); $enabled = ai_seo_cro_is_force_https_enabled(); $is_local = ai_seo_cro_is_local_url($home_url); $htaccess_path = ai_seo_cro_get_force_https_htaccess_path(); $htaccess_redirect_enabled = ai_seo_cro_has_force_https_htaccess_rules(); $hsts_enabled = ai_seo_cro_has_hsts_htaccess_rules(); $htaccess_enabled = $htaccess_redirect_enabled && $hsts_enabled; $htaccess_writable = ai_seo_cro_can_write_force_https_htaccess(); return [ 'success' => true, 'enabled' => $enabled, 'home_url' => $home_url, 'https_url' => $https_url, 'is_local' => $is_local, 'htaccess_path' => $htaccess_path, 'htaccess_enabled' => $htaccess_enabled, 'htaccess_redirect_enabled' => $htaccess_redirect_enabled, 'hsts_enabled' => $hsts_enabled, 'htaccess_writable' => $htaccess_writable, 'redirect_code' => 301, 'message' => $enabled ? ($htaccess_enabled ? 'Force HTTPS and HSTS are enabled in .htaccess.' : 'Force HTTPS is enabled, but the .htaccess redirect or HSTS header rules are missing.') : 'Force HTTPS is disabled.', ]; } function ai_seo_cro_update_force_https($enabled = true) { $htaccess_result = ai_seo_cro_update_force_https_htaccess($enabled); if (empty($htaccess_result['success'])) { $status = ai_seo_cro_get_force_https_status(); $status['success'] = false; $status['message'] = $htaccess_result['message'] ?? 'Unable to update .htaccess.'; $status['htaccess_result'] = $htaccess_result; return $status; } update_option('ai_seo_cro_enable_force_https', $enabled ? '1' : '0'); $status = ai_seo_cro_get_force_https_status(); $status['htaccess_result'] = $htaccess_result; $status['message'] = $enabled ? 'Force HTTPS and HSTS enabled. HTTP requests will redirect to HTTPS and HTTPS responses will include the HSTS header from .htaccess.' : 'Force HTTPS disabled. The managed .htaccess redirect block was removed.'; return $status; }