0 && ( time() - $ran_at ) <= self::CACHE_TTL ) { return $fallback; } } return array(); } public static function clear_cache(): void { delete_transient( self::TRANSIENT_KEY ); delete_option( self::OPTION_KEY ); } public static function run_and_cache( string $target_url, bool $force = false ): array { if ( $force ) { self::clear_cache(); } $results = self::run_checks( $target_url ); set_transient( self::TRANSIENT_KEY, $results, self::CACHE_TTL ); update_option( self::OPTION_KEY, $results, false ); return $results; } private static function run_checks( string $target_url ): array { $target_url = self::normalize_target_url( $target_url ); $items = array(); $items[] = self::check_search_visibility(); $items[] = self::check_permalink_structure(); $resp = self::fetch_url( $target_url ); $items[] = self::check_fetch_ok( $target_url, $resp ); $items[] = self::check_x_robots_tag_header( $resp ); $html = isset( $resp['body'] ) ? (string) $resp['body'] : ''; $items[] = self::check_meta_robots_noindex( $html ); $items[] = self::check_title_tag( $html ); $items[] = self::check_canonical_tag( $html ); $items[] = self::check_mixed_content( $html ); $items[] = self::check_recent_titles(); $items[] = self::check_robots_txt(); $items[] = self::check_sitemaps(); return array( 'ran_at' => time(), 'target_url' => $target_url, 'items' => $items, ); } private static function normalize_target_url( string $url ): string { $url = trim( $url ); if ( '' === $url ) { return home_url( '/' ); } // Allow relative paths. if ( 0 === strpos( $url, '/' ) ) { $url = home_url( $url ); } $url = esc_url_raw( $url ); if ( '' === $url ) { return home_url( '/' ); } $home_host = wp_parse_url( home_url( '/' ), PHP_URL_HOST ); $u_host = wp_parse_url( $url, PHP_URL_HOST ); if ( empty( $home_host ) || empty( $u_host ) || 0 !== strcasecmp( (string) $home_host, (string) $u_host ) ) { return home_url( '/' ); } return $url; } private static function fetch_url( string $url ): array { $args = array( 'timeout' => 8, 'redirection' => 3, 'reject_unsafe_urls' => true, 'limit_response_size' => 262144, // 256 KB safety. 'user-agent' => 'SSC Real SEO Baseline/' . SSC_REAL_SEO_VERSION . '; ' . home_url( '/' ), ); $response = wp_remote_get( $url, $args ); if ( is_wp_error( $response ) ) { return array( 'ok' => false, 'code' => 0, 'error' => $response->get_error_message(), 'headers' => array(), 'body' => '', ); } $code = (int) wp_remote_retrieve_response_code( $response ); $body = (string) wp_remote_retrieve_body( $response ); $headers = wp_remote_retrieve_headers( $response ); $headers_array = array(); if ( is_array( $headers ) ) { $headers_array = $headers; } elseif ( is_object( $headers ) ) { $headers_array = (array) $headers; } return array( 'ok' => ( $code >= 200 && $code < 400 ), 'code' => $code, 'error' => '', 'headers' => $headers_array, 'body' => $body, ); } private static function status_item( string $checked, string $status, string $found, string $why, string $next ): array { return array( 'checked' => $checked, 'status' => $status, // pass|warning|fail 'found' => $found, 'why' => $why, 'next' => $next, ); } private static function check_search_visibility(): array { $blog_public = (int) get_option( 'blog_public', 1 ); if ( 1 === $blog_public ) { return self::status_item( __( 'Search engine visibility setting', '7-sided-cube-real-seo' ), 'pass', __( 'Search engines are allowed to index this site.', '7-sided-cube-real-seo' ), __( 'If this is disabled, your site can be hidden from search engines.', '7-sided-cube-real-seo' ), __( 'Keep this enabled for most public websites.', '7-sided-cube-real-seo' ) ); } return self::status_item( __( 'Search engine visibility setting', '7-sided-cube-real-seo' ), 'fail', __( 'Search engines are discouraged from indexing this site.', '7-sided-cube-real-seo' ), __( 'This can prevent your pages from appearing in search results.', '7-sided-cube-real-seo' ), __( 'Go to Settings > Reading and uncheck the visibility option.', '7-sided-cube-real-seo' ) ); } private static function check_permalink_structure(): array { $structure = (string) get_option( 'permalink_structure', '' ); if ( '' === $structure ) { return self::status_item( __( 'Permalink structure', '7-sided-cube-real-seo' ), 'warning', __( 'Permalinks are set to Plain.', '7-sided-cube-real-seo' ), __( 'Pretty permalinks are easier to read and share, and often make analytics and internal linking clearer.', '7-sided-cube-real-seo' ), __( 'Go to Settings > Permalinks and choose a pretty structure like Post name.', '7-sided-cube-real-seo' ) ); } return self::status_item( __( 'Permalink structure', '7-sided-cube-real-seo' ), 'pass', __( 'Pretty permalinks are enabled.', '7-sided-cube-real-seo' ), __( 'Clean URLs support a stronger baseline and cleaner internal linking.', '7-sided-cube-real-seo' ), __( 'No action needed.', '7-sided-cube-real-seo' ) ); } private static function check_fetch_ok( string $url, array $resp ): array { if ( ! empty( $resp['ok'] ) ) { return self::status_item( __( 'Page fetch', '7-sided-cube-real-seo' ), 'pass', sprintf( /* translators: %d: HTTP status code */ __( 'Fetched successfully (HTTP %d).', '7-sided-cube-real-seo' ), (int) $resp['code'] ), __( 'If your pages cannot be fetched, search engines can struggle to crawl them.', '7-sided-cube-real-seo' ), __( 'No action needed.', '7-sided-cube-real-seo' ) ); } $msg = isset( $resp['error'] ) && '' !== $resp['error'] ? $resp['error'] : __( 'Request failed.', '7-sided-cube-real-seo' ); return self::status_item( __( 'Page fetch', '7-sided-cube-real-seo' ), 'fail', /* translators: Placeholder values such as HTTP status text and code. */ sprintf( __( 'Could not fetch page. %s', '7-sided-cube-real-seo' ), $msg ), __( 'If WordPress cannot fetch the page internally, it can be a sign of firewall rules, redirects, or server issues.', '7-sided-cube-real-seo' ), __( 'Try again. If it persists, check redirects, security plugins, or host firewall settings.', '7-sided-cube-real-seo' ) ); } private static function check_x_robots_tag_header( array $resp ): array { $headers = isset( $resp['headers'] ) && is_array( $resp['headers'] ) ? $resp['headers'] : array(); $value = ''; foreach ( $headers as $k => $v ) { if ( 0 === strcasecmp( (string) $k, 'x-robots-tag' ) ) { $value = is_array( $v ) ? implode( ', ', $v ) : (string) $v; break; } } if ( '' === $value ) { return self::status_item( __( 'X-Robots-Tag header', '7-sided-cube-real-seo' ), 'pass', __( 'No X-Robots-Tag header found.', '7-sided-cube-real-seo' ), __( 'Some systems use this header to apply noindex or nofollow sitewide.', '7-sided-cube-real-seo' ), __( 'No action needed.', '7-sided-cube-real-seo' ) ); } $lower = strtolower( $value ); if ( false !== strpos( $lower, 'noindex' ) ) { return self::status_item( __( 'X-Robots-Tag header', '7-sided-cube-real-seo' ), 'fail', /* translators: Placeholder values such as HTTP status text and code. */ sprintf( __( 'Header includes: %s', '7-sided-cube-real-seo' ), $value ), __( 'A noindex header can prevent pages from appearing in search results.', '7-sided-cube-real-seo' ), __( 'Check server headers, security plugins, or edge caching rules that may be adding this.', '7-sided-cube-real-seo' ) ); } return self::status_item( __( 'X-Robots-Tag header', '7-sided-cube-real-seo' ), 'warning', /* translators: Placeholder values such as HTTP status text and code. */ sprintf( __( 'Header includes: %s', '7-sided-cube-real-seo' ), $value ), __( 'Robots headers can influence indexing and crawling behavior.', '7-sided-cube-real-seo' ), __( 'Review the header value and confirm it is intentional.', '7-sided-cube-real-seo' ) ); } private static function check_meta_robots_noindex( string $html ): array { $robots = self::find_meta_robots( $html ); if ( '' === $robots ) { return self::status_item( __( 'Meta robots tag', '7-sided-cube-real-seo' ), 'pass', __( 'No meta robots tag found.', '7-sided-cube-real-seo' ), __( 'A meta robots tag can block indexing when it includes noindex.', '7-sided-cube-real-seo' ), __( 'No action needed.', '7-sided-cube-real-seo' ) ); } $lower = strtolower( $robots ); if ( false !== strpos( $lower, 'noindex' ) ) { return self::status_item( __( 'Meta robots tag', '7-sided-cube-real-seo' ), 'fail', /* translators: Placeholder values such as HTTP status text and code. */ sprintf( __( 'Found robots content: %s', '7-sided-cube-real-seo' ), $robots ), __( 'If a page has a noindex directive, it can be kept out of search results.', '7-sided-cube-real-seo' ), __( 'Remove noindex if this page should be indexed.', '7-sided-cube-real-seo' ) ); } return self::status_item( __( 'Meta robots tag', '7-sided-cube-real-seo' ), 'warning', /* translators: Placeholder values such as HTTP status text and code. */ sprintf( __( 'Found robots content: %s', '7-sided-cube-real-seo' ), $robots ), __( 'Robots directives can influence indexing and crawling behavior.', '7-sided-cube-real-seo' ), __( 'Review to confirm it matches your intent.', '7-sided-cube-real-seo' ) ); } private static function check_title_tag( string $html ): array { if ( preg_match( '/