resolve_search_term( $context ); $proxy_args = isset( $context['proxy_args'] ) && is_array( $context['proxy_args'] ) ? $context['proxy_args'] : array(); $selected_image = isset( $context['selected_image'] ) ? $context['selected_image'] : 'first_result'; $log = isset( $context['log'] ) ? $context['log'] : null; $page = isset( $context['page'] ) ? max( 1, intval( $context['page'] ) ) : 1; $using_cloudflare = $this->is_cloudflare_proxy_enabled( $context ); if ( empty( $api_key ) && ! $using_cloudflare ) { return new WP_Error( 'ALLSI_google_image_missing_key', __( 'Google Custom Search key is missing.', 'all-sources-images' ) ); } if ( empty( $cx_id ) ) { return new WP_Error( 'ALLSI_google_image_missing_cx', __( 'Google Custom Search CX ID is missing.', 'all-sources-images' ) ); } if ( '' === trim( $search_term ) ) { return new WP_Error( 'ALLSI_google_image_missing_query', __( 'No search query available for Google Images.', 'all-sources-images' ) ); } $query_args = $this->build_query_args( $bank_options, $api_key, $cx_id, $search_term, $page ); $request_args = $this->merge_proxy_args( array( 'timeout' => 30, 'method' => 'GET', 'redirection' => 5, 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', 'reject_unsafe_urls' => false, 'sslverify' => false, ), $proxy_args ); $request_url = add_query_arg( $query_args, self::API_ENDPOINT ); $response = $this->request_with_proxy( 'google_image', $request_url, $request_args, $context ); if ( $log ) { $log->info( 'Google Image request', array( 'post' => isset( $context['post_id'] ) ? $context['post_id'] : 0, 'query' => $search_term, 'url' => $request_url, ) ); } if ( is_wp_error( $response ) ) { if ( $log ) { $log->error( 'Google Image transport error', array( 'post' => isset( $context['post_id'] ) ? $context['post_id'] : 0, 'error' => $response->get_error_message(), ) ); } return $response; } $status_code = wp_remote_retrieve_response_code( $response ); $body_raw = wp_remote_retrieve_body( $response ); $payload = json_decode( $body_raw, true ); if ( 200 !== intval( $status_code ) || ! is_array( $payload ) ) { if ( $log ) { $log->error( 'Google Image HTTP error', array( 'status' => $status_code, 'body' => $this->truncate_body( $body_raw ), ) ); } return new WP_Error( 'ALLSI_google_image_http_error', __( 'Unexpected response from Google Custom Search.', 'all-sources-images' ), array( 'status' => $status_code, 'body' => $body_raw, ) ); } if ( ! empty( $context['get_only_thumb'] ) ) { return $payload; } $items = isset( $payload['items'] ) && is_array( $payload['items'] ) ? $payload['items'] : array(); if ( empty( $items ) ) { if ( $log ) { $log->warning( 'Google Image returned no results', array( 'query' => $search_term, 'body' => $this->truncate_body( $body_raw ), ) ); } return new WP_Error( 'ALLSI_google_image_no_results', __( 'Google Custom Search returned no images.', 'all-sources-images' ) ); } if ( 'random_result' === $selected_image ) { shuffle( $items ); } $translator = $this->get_translator_callable( $context ); $source_label = __( 'Google Images', 'all-sources-images' ); foreach ( $items as $item ) { $image_url = $this->extract_image_url( $item ); if ( empty( $image_url ) ) { continue; } $file_media = $this->download_image( $image_url, $proxy_args ); if ( is_wp_error( $file_media ) ) { continue; } $site_label = isset( $item['displayLink'] ) ? $item['displayLink'] : ''; $alt_text = ALLSI_Source_Text_Helper::build_alt_text( $global_options, $search_term, $source_label, $translator ); $caption = ALLSI_Source_Text_Helper::build_caption( $global_options, $site_label, $source_label ); return array( 'url_results' => $image_url, 'file_media' => $file_media, 'alt_img' => $alt_text, 'caption_img' => $caption, 'raw_response'=> $payload, 'source_url' => isset( $item['link'] ) ? $item['link'] : '', ); } return new WP_Error( 'ALLSI_google_image_download_failed', __( 'Unable to download a valid Google image.', 'all-sources-images' ) ); } private function resolve_search_term( array $context ) { if ( ! empty( $context['search'] ) ) { return str_replace( '…', '', $context['search'] ); } if ( isset( $context['img_block']['based_on']['title'] ) ) { return str_replace( '…', '', $context['img_block']['based_on']['title'] ); } return ''; } private function build_query_args( array $bank_options, $api_key, $cx_id, $search_term, $page = 1 ) { $country = ! empty( $bank_options['search_country'] ) ? $bank_options['search_country'] : 'en'; $img_color = ! empty( $bank_options['img_color'] ) ? $bank_options['img_color'] : ''; $filetype = ! empty( $bank_options['filetype'] ) ? $bank_options['filetype'] : ''; $imgsz = ! empty( $bank_options['imgsz'] ) ? $bank_options['imgsz'] : ''; $imgtype = ! empty( $bank_options['imgtype'] ) ? $bank_options['imgtype'] : ''; $safe = ! empty( $bank_options['safe'] ) ? $bank_options['safe'] : 'medium'; if ( 'moderate' === $safe ) { $safe = 'medium'; } $rights = $this->build_rights_filter( $bank_options ); $page = max( 1, intval( $page ) ); $args = array( 'key' => $api_key, 'cx' => $cx_id, 'q' => $search_term, 'searchType' => 'image', 'num' => 10, 'hl' => $country, 'safe' => $safe, 'userIp' => isset( $_SERVER['SERVER_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_ADDR'] ) ) : '0.0.0.0', 'start' => 1, ); $calculated_start = ( ( $page - 1 ) * $args['num'] ) + 1; // Google Custom Search only returns up to start index 91 $args['start'] = max( 1, min( $calculated_start, 91 ) ); if ( ! empty( $img_color ) ) { $args['imgDominantColor'] = $img_color; } if ( ! empty( $filetype ) ) { $args['fileType'] = $filetype; } if ( ! empty( $imgsz ) ) { $args['imgSize'] = $imgsz; } if ( ! empty( $imgtype ) ) { $args['imgType'] = $imgtype; } if ( ! empty( $rights ) ) { $args['rights'] = $rights; } return $args; } private function build_rights_filter( array $bank_options ) { if ( empty( $bank_options['rights'] ) ) { return ''; } $rights_values = array_filter( array_map( 'sanitize_text_field', (array) $bank_options['rights'] ) ); if ( empty( $rights_values ) ) { return ''; } return '(' . implode( '|', $rights_values ) . ')'; } private function extract_image_url( array $item ) { if ( isset( $item['pagemap']['cse_image'][0]['src'] ) && ! empty( $item['pagemap']['cse_image'][0]['src'] ) ) { return $item['pagemap']['cse_image'][0]['src']; } if ( isset( $item['link'] ) && ! empty( $item['link'] ) ) { return $item['link']; } return ''; } private function download_image( $url, array $proxy_args ) { $request_args = $this->merge_proxy_args( array( 'timeout' => 30, 'redirection' => 9, 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', 'reject_unsafe_urls' => false, 'sslverify' => false, ), $proxy_args ); $response = wp_remote_request( $url, $request_args ); if ( is_wp_error( $response ) ) { return $response; } $status_code = wp_remote_retrieve_response_code( $response ); $content_type = wp_remote_retrieve_header( $response, 'content-type' ); if ( 200 !== intval( $status_code ) || ( is_string( $content_type ) && false !== strpos( $content_type, 'text/html' ) ) ) { return new WP_Error( 'ALLSI_google_image_invalid_media', __( 'Google returned an invalid image payload.', 'all-sources-images' ) ); } return $response; } private function truncate_body( $body, $limit = 600 ) { if ( ! is_string( $body ) ) { return ''; } if ( strlen( $body ) <= $limit ) { return $body; } return substr( $body, 0, $limit ) . '...'; } private function get_translator_callable( array $context ) { if ( isset( $context['generation'] ) && method_exists( $context['generation'], 'ALLSI_translate_text' ) ) { return array( $context['generation'], 'ALLSI_translate_text' ); } return null; } }