get_col($wpdb->prepare( "SELECT DISTINCT url FROM {$table_name} WHERE status_code = 0 LIMIT %d", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $batch_size )); if (empty($unique_urls)) { return 0; } $requests = array(); $results = array(); // 2. Distribute checks (Internal vs External) foreach ($unique_urls as $url) { $clean_url = trim(html_entity_decode($url)); // IF LINK IS INTERNAL (Including AILM Auto) -> Skip HTTP ping if (strpos($clean_url, $home_url) === 0) { $post_id = url_to_postid($clean_url); if ($post_id > 0 && get_post_status($post_id) === 'publish') { $results[$url] = 200; // Post exists, set 200 instantly continue; } // If url_to_postid didn't find it (e.g., category or tag link), add to HTTP ping queue } // Prepare request for external links and complex internal ones $requests[$url] = array( 'url' => $clean_url, 'type' => 'HEAD', 'options' => array('timeout' => 5, 'redirection' => 5, 'verify' => false), 'headers' => array( // Disguise as a real browser to avoid 403 from Google and Cloudflare 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' ) ); } // 3. Send HTTP requests in parallel if (!empty($requests)) { $responses = Requests::request_multiple($requests); foreach ($responses as $url => $response) { $status_code = 500; if (!is_wp_error($response) && !($response instanceof Exception) && !($response instanceof Requests_Exception)) { $status_code = (int) $response->status_code; // Fallback 1: If server rejected HEAD request (403, 405), try regular GET if (in_array($status_code, [400, 403, 405, 406, 503])) { $fallback = wp_remote_get($url, array( 'timeout' => 5, 'redirection' => 5, 'sslverify' => false, 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0' )); if (!is_wp_error($fallback)) { $status_code = (int) wp_remote_retrieve_response_code($fallback); } } // Fallback 2: If http:// returned an error, try substituting https:// if ($status_code >= 400 && strpos($url, 'http://') === 0) { $https_url = str_replace('http://', 'https://', $url); $https_fallback = wp_remote_head($https_url, array('timeout' => 5, 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0')); if (!is_wp_error($https_fallback)) { $https_code = (int) wp_remote_retrieve_response_code($https_fallback); if ($https_code == 200 || $https_code == 301 || $https_code == 302) { $status_code = 200; // Forgive if HTTPS version works } } } } $results[$url] = $status_code; } } // 4. Bulk update the database $now = current_time('mysql'); foreach ($results as $url => $status_code) { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->query($wpdb->prepare( "UPDATE {$table_name} SET status_code = %d, last_checked = %s WHERE url = %s AND status_code = 0", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $status_code, $now, $url )); } return count($unique_urls); } }