PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 1.1.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v1.1.0
2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.10.0 All 48 releases
thinkrank / includes / integrations / class-google-api-base-client.php

class-google-api-base-client.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 1.1.0, at includes/integrations/class-google-api-base-client.php

203 lines 5.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Google API Base Client Class
4 *
5 * Abstract base class for Google API integrations providing common functionality
6 * for HTTP requests, rate limiting, error handling, and response processing.
7 * Follows ThinkRank patterns established by Claude_Client and OpenAI_Client.
8 *
9 * @package ThinkRank\Integrations
10 * @since 1.0.0
11 */
12
13 declare(strict_types=1);
14
15 namespace ThinkRank\Integrations;
16
17 // Prevent direct access
18 if (!defined('ABSPATH')) {
19 exit;
20 }
21
22 /**
23 * Google API Base Client Class
24 *
25 * Single Responsibility: Provide common Google API functionality
26 * Following ThinkRank HTTP client patterns from Claude_Client and OpenAI_Client
27 *
28 * @since 1.0.0
29 */
30 abstract class Google_API_Base_Client {
31
32 /**
33 * API key
34 *
35 * @var string
36 */
37 protected string $api_key;
38
39 /**
40 * Request timeout in seconds
41 *
42 * @var int
43 */
44 protected int $timeout;
45
46 /**
47 * Rate limit configuration
48 *
49 * @var array
50 */
51 protected array $rate_limits;
52
53 /**
54 * Constructor
55 *
56 * @param string $api_key Google API key
57 * @param int $timeout Request timeout in seconds
58 */
59 public function __construct(string $api_key, int $timeout = 300) {
60 $this->api_key = $api_key;
61 $this->timeout = $timeout;
62 $this->rate_limits = $this->get_rate_limits();
63 }
64
65 /**
66 * Make HTTP request to Google API
67 * Following Claude_Client and OpenAI_Client patterns
68 *
69 * @param string $url Full API URL
70 * @param array $params Request parameters
71 * @param string $method HTTP method
72 * @return array Response data
73 * @throws \Exception If request fails
74 */
75 protected function make_request(string $url, array $params = [], string $method = 'GET'): array {
76 // Check rate limiting before making request
77 $this->check_rate_limit();
78
79 $args = [
80 'timeout' => $this->timeout,
81 'headers' => [
82 'User-Agent' => 'ThinkRank/' . THINKRANK_VERSION,
83 ],
84 'method' => $method
85 ];
86
87 if ($method === 'GET' && !empty($params)) {
88 $url .= '?' . http_build_query($params);
89 } elseif ($method === 'POST') {
90 $args['body'] = wp_json_encode($params);
91 $args['headers']['Content-Type'] = 'application/json';
92 }
93
94 $response = wp_remote_request($url, $args);
95
96 if (is_wp_error($response)) {
97 throw new \Exception('API request failed: ' . esc_html($response->get_error_message()));
98 }
99
100 $status_code = wp_remote_retrieve_response_code($response);
101 $response_body = wp_remote_retrieve_body($response);
102
103 if ($status_code >= 400) {
104 $error_data = json_decode($response_body, true);
105 $error_message = $error_data['error']['message'] ?? 'Unknown API error';
106 throw new \Exception(sprintf('Google API error (%d): %s', (int) $status_code, esc_html($error_message)));
107 }
108
109 $data = json_decode($response_body, true);
110
111 if (json_last_error() !== JSON_ERROR_NONE) {
112 throw new \Exception('Invalid JSON response from Google API');
113 }
114
115 // Update rate limit tracking after successful request
116 $this->update_rate_limit();
117
118 return $data;
119 }
120
121 /**
122 * Test API connection
123 * Must be implemented by concrete classes
124 *
125 * @return array Connection test results
126 */
127 abstract public function test_connection(): array;
128
129 /**
130 * Get rate limit configuration
131 * Must be implemented by concrete classes
132 *
133 * @return array Rate limit configuration
134 */
135 abstract protected function get_rate_limits(): array;
136
137 /**
138 * Check if request is within rate limits
139 * Following ThinkRank rate limiting patterns from existing classes
140 *
141 * @throws \Exception If rate limit exceeded
142 */
143 protected function check_rate_limit(): void {
144 $rate_limit_key = $this->get_rate_limit_key();
145 $current_time = time();
146
147 // Reset counter if it's a new day
148 if ($current_time >= $this->rate_limits['reset_time']) {
149 $this->reset_rate_limit_counter();
150 }
151
152 $current_count = get_transient($rate_limit_key . '_count') ?: 0;
153
154 if ($current_count >= $this->rate_limits['max_requests_per_day']) {
155 throw new \Exception(esc_html($this->get_rate_limit_error_message()));
156 }
157 }
158
159 /**
160 * Update rate limit counter after successful request
161 * Following ThinkRank transient patterns
162 */
163 protected function update_rate_limit(): void {
164 $rate_limit_key = $this->get_rate_limit_key();
165 $current_count = get_transient($rate_limit_key . '_count') ?: 0;
166 $new_count = $current_count + 1;
167
168 // Set transient to expire at end of day
169 $seconds_until_tomorrow = strtotime('tomorrow') - time();
170 set_transient($rate_limit_key . '_count', $new_count, $seconds_until_tomorrow);
171 }
172
173 /**
174 * Reset rate limit counter for new day
175 */
176 private function reset_rate_limit_counter(): void {
177 $rate_limit_key = $this->get_rate_limit_key();
178 delete_transient($rate_limit_key . '_count');
179 delete_transient($rate_limit_key . '_reset');
180
181 // Set new reset time for tomorrow
182 $seconds_until_tomorrow = strtotime('tomorrow') - time();
183 set_transient($rate_limit_key . '_reset', strtotime('tomorrow'), $seconds_until_tomorrow);
184 $this->rate_limits['reset_time'] = strtotime('tomorrow');
185 }
186
187 /**
188 * Get rate limit transient key
189 * Following ThinkRank option naming patterns
190 *
191 * @return string Rate limit key
192 */
193 abstract protected function get_rate_limit_key(): string;
194
195 /**
196 * Get rate limit error message
197 * Must be implemented by concrete classes
198 *
199 * @return string Error message
200 */
201 abstract protected function get_rate_limit_error_message(): string;
202 }
203