PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.5.23
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.5.23
2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 All 139 releases
metasync / google-index / class-google-index-admin.php

class-google-index-admin.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.5.23, at google-index/class-google-index-admin.php

478 lines 19.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Google Index - Admin Integration
5 *
6 * Integrates Google Index settings into MetaSync admin general settings
7 *
8 * @package GoogleIndexDirect
9 * @version 1.0.0
10 */
11
12 // Prevent direct access
13 if (!defined('ABSPATH')) {
14 exit;
15 }
16
17 class Google_Index_Admin
18 {
19 /**
20 * Section ID for Google Index settings
21 */
22 private const SECTION_GOOGLE_INDEX = 'google_index_direct_settings';
23
24 /**
25 * Initialize admin functionality
26 */
27 public function __construct()
28 {
29 // Hook into MetaSync admin initialization
30 add_action('admin_init', array($this, 'add_settings_to_metasync'), 20);
31 add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
32
33 // Hook into MetaSync's AJAX settings processing
34 add_action('wp_ajax_meta_sync_save_settings', array($this, 'process_google_index_settings'), 5);
35
36 // Display admin notices after redirect
37 add_action('admin_notices', array($this, 'display_admin_notices'));
38
39 // AJAX handlers
40 add_action('wp_ajax_google_index_direct_test', array($this, 'ajax_test_connection'));
41 }
42
43
44 /**
45 * Add Google Index settings to MetaSync admin
46 */
47 public function add_settings_to_metasync()
48 {
49 // Only add if MetaSync Admin class exists
50 if (!class_exists('Metasync_Admin')) {
51 return;
52 }
53
54 // Get MetaSync page slug
55 $page_slug = $this->get_metasync_page_slug();
56 if (!$page_slug) {
57 return;
58 }
59
60 // Add settings section for Google Index
61 add_settings_section(
62 self::SECTION_GOOGLE_INDEX,
63 '', // Empty title - we'll use dashboard card styling
64 function(){}, // Empty callback
65 $page_slug . '_general'
66 );
67
68 // Add the main settings field
69 add_settings_field(
70 'google_index_direct_config',
71 'Google Index API',
72 array($this, 'render_settings_field'),
73 $page_slug . '_general',
74 self::SECTION_GOOGLE_INDEX
75 );
76 }
77
78 /**
79 * Get MetaSync page slug
80 */
81 private function get_metasync_page_slug()
82 {
83 if (class_exists('Metasync_Admin') && property_exists('Metasync_Admin', 'page_slug')) {
84 return Metasync_Admin::$page_slug;
85 }
86 return 'searchatlas'; // fallback
87 }
88
89 /**
90 * Render the Google Index settings field
91 */
92 public function render_settings_field()
93 {
94 // Load Google Index functionality
95 if (!function_exists('google_index_direct')) {
96 require_once plugin_dir_path(__FILE__) . 'google-index-init.php';
97 }
98
99 // Get current service account info (safe - doesn't expose private key)
100 $google_index = google_index_direct();
101 $service_info = $google_index->get_service_account_info();
102 $is_configured = !isset($service_info['error']);
103
104 // Include the settings field view
105 include plugin_dir_path(__FILE__) . '../views/metasync-google-index-api-settings.php';
106 }
107
108 /**
109 * Process Google Index settings during MetaSync AJAX save
110 * This runs early in the AJAX processing chain (priority 5)
111 */
112 public function process_google_index_settings()
113 {
114 // Only process if our fields are present in the request
115 if (!isset($_POST['google_index_service_account_json']) &&
116 !isset($_POST['google_index_clear_config']) &&
117 !isset($_FILES['google_index_service_account_file'])) {
118 return; // No Google Index data to process
119 }
120
121 // Load Google Index functionality
122 if (!function_exists('google_index_save_service_account')) {
123 require_once plugin_dir_path(__FILE__) . 'google-index-init.php';
124 }
125
126 $service_account_json = '';
127
128 // Get JSON from textarea
129 if (isset($_POST['google_index_service_account_json'])) {
130 $service_account_json = sanitize_textarea_field(wp_unslash($_POST['google_index_service_account_json']));
131 }
132
133 // Override with file upload if provided
134 if (isset($_FILES['google_index_service_account_file']) &&
135 !empty($_FILES['google_index_service_account_file']['tmp_name']) &&
136 file_exists($_FILES['google_index_service_account_file']['tmp_name'])) {
137
138 $uploaded_json = file_get_contents($_FILES['google_index_service_account_file']['tmp_name']);
139 if ($uploaded_json !== false) {
140 $service_account_json = $uploaded_json; // Removed unnecessary wp_unslash
141 }
142 }
143
144 // Handle clear configuration
145 if (isset($_POST['google_index_clear_config'])) {
146 delete_option('google_index_service_account');
147 // Success messages shown after redirect (to prevent interfering with MetaSync flow)
148 $this->add_settings_notice('Service account configuration cleared successfully!', 'success');
149 }
150 // Process service account JSON if provided
151 elseif (!empty($service_account_json) && trim($service_account_json) !== '') {
152
153 // Skip if it's just the placeholder text
154 if (strpos($service_account_json, 'Service account configured') !== false) {
155 return; // Don't process placeholder text
156 }
157
158 // Decode and validate JSON
159 $service_account_data = json_decode($service_account_json, true);
160
161 if (json_last_error() !== JSON_ERROR_NONE) {
162 // JSON parsing error - send immediate error response
163 $json_error_message = 'Invalid JSON format';
164 switch (json_last_error()) {
165 case JSON_ERROR_SYNTAX:
166 $json_error_message .= ' - Syntax error in JSON';
167 break;
168 case JSON_ERROR_UTF8:
169 $json_error_message .= ' - Invalid UTF-8 encoding';
170 break;
171 default:
172 $json_error_message .= ' - ' . json_last_error_msg();
173 break;
174 }
175
176 wp_send_json_error([
177 'errors' => ['Google Index: ' . $json_error_message . '. Please check your service account JSON.']
178 ]);
179 }
180
181 if (!is_array($service_account_data)) {
182 wp_send_json_error([
183 'errors' => ['Google Index: JSON must be an object/array. Please check your service account JSON format.']
184 ]);
185 }
186
187 // Validate required fields
188 $required_fields = ['type', 'project_id', 'private_key_id', 'private_key', 'client_email', 'client_id', 'auth_uri', 'token_uri'];
189 $missing_fields = [];
190
191 foreach ($required_fields as $field) {
192 if (!isset($service_account_data[$field]) || empty($service_account_data[$field])) {
193 $missing_fields[] = $field;
194 }
195 }
196
197 if (!empty($missing_fields)) {
198 wp_send_json_error([
199 'errors' => ['Google Index: Missing required fields - ' . implode(', ', $missing_fields) . '. Please ensure you have a complete service account JSON.']
200 ]);
201 }
202
203 // Save using Google Index function
204 $result = google_index_save_service_account($service_account_data);
205
206 if ($result) {
207 $this->add_settings_notice('Google Index service account configured successfully!', 'success');
208 } else {
209 // Send immediate error response using MetaSync's expected format
210 wp_send_json_error([
211 'errors' => ['Google Index: Failed to save service account configuration. Please try again or check your JSON format.']
212 ]);
213 }
214 }
215 }
216
217 /**
218 * Add a settings notice to be displayed after AJAX save
219 *
220 * @param string $message Notice message
221 * @param string $type Notice type: 'success', 'error', 'warning', 'info'
222 */
223 private function add_settings_notice($message, $type = 'info')
224 {
225 $notices = get_transient('google_index_admin_notices') ?: [];
226 $notices[] = [
227 'message' => $message,
228 'type' => $type,
229 'time' => time()
230 ];
231
232 // Store notices for 30 seconds (enough time for page redirect)
233 set_transient('google_index_admin_notices', $notices, 30);
234 }
235
236 /**
237 * Display admin notices for Google Index settings
238 */
239 public function display_admin_notices()
240 {
241 // Only show notices on MetaSync settings pages
242 $page_slug = $this->get_metasync_page_slug();
243 $current_screen = get_current_screen();
244
245 if (!$current_screen || strpos($current_screen->id, $page_slug) === false) {
246 return;
247 }
248
249 // Get and display notices
250 $notices = get_transient('google_index_admin_notices');
251 if (!empty($notices)) {
252 foreach ($notices as $notice) {
253 $class = 'notice notice-' . esc_attr($notice['type']) . ' is-dismissible';
254 echo '<div class="' . $class . '">';
255 echo '<p><strong>Google Index:</strong> ' . esc_html($notice['message']) . '</p>';
256 echo '</div>';
257 }
258
259 // Clear notices after displaying
260 delete_transient('google_index_admin_notices');
261 }
262 }
263
264 /**
265 * AJAX handler for testing connection
266 */
267 public function ajax_test_connection()
268 {
269 // Check nonce and permissions
270 if (!wp_verify_nonce($_POST['nonce'] ?? '', 'google_index_direct_test') ||
271 !Metasync::current_user_has_plugin_access()) {
272 wp_die('Security check failed');
273 }
274
275 // Load Google Index functionality
276 if (!function_exists('google_index_direct')) {
277 require_once plugin_dir_path(__FILE__) . 'google-index-init.php';
278 }
279
280 try {
281 // Test the connection
282 $google_index = google_index_direct();
283 $test_results = $google_index->test_connection();
284
285 wp_send_json_success([
286 'message' => 'Connection test completed',
287 'results' => $test_results
288 ]);
289
290 } catch (Exception $e) {
291 wp_send_json_error([
292 'message' => 'Test failed: ' . $e->getMessage()
293 ]);
294 }
295 }
296
297 /**
298 * Enqueue admin scripts and styles
299 */
300 public function enqueue_admin_scripts($hook)
301 {
302 // Only load on MetaSync settings pages
303 $page_slug = $this->get_metasync_page_slug();
304 if (strpos($hook, $page_slug) === false) {
305 return;
306 }
307
308 // Only load on general tab (default tab when none specified)
309 $current_tab = isset($_GET['tab']) ? $_GET['tab'] : 'general';
310 if ($current_tab !== 'general') {
311 return;
312 }
313
314 // Add inline JavaScript for functionality
315 wp_add_inline_script('jquery', $this->get_admin_javascript());
316 }
317
318 /**
319 * Get JavaScript for admin functionality
320 *
321 * @return string JavaScript code
322 */
323 private function get_admin_javascript()
324 {
325 $nonce = wp_create_nonce('google_index_direct_test');
326
327 return "
328 jQuery(document).ready(function($) {
329 // Integration with MetaSync's unsaved changes detection
330 function integrateWithUnsavedChangesDetection() {
331 // Monitor textarea for changes (avoid recursion)
332 $('#google_index_service_account_json').on('input change paste keyup', function(e) {
333 console.log('Google Index: Textarea changed via', e.type);
334 // Trigger MetaSync's change detection (works on both Settings and Indexation Control pages)
335 $('#metaSyncGeneralSetting, #metaSyncSeoControlsForm').trigger('change');
336 });
337
338 // Handle file upload with auto-populate and change detection
339 $('#google_index_service_account_file').on('change', function(e) {
340 var file = e.target.files[0];
341 var textarea = $('#google_index_service_account_json');
342
343 if (file && file.type === 'application/json') {
344 var reader = new FileReader();
345 reader.onload = function(e) {
346 try {
347 var json = JSON.parse(e.target.result);
348 // Update textarea value
349 var jsonString = JSON.stringify(json, null, 2);
350 textarea.val(jsonString);
351
352 // Create and dispatch native events to ensure proper detection
353 setTimeout(function() {
354 // Create native events
355 var inputEvent = new Event('input', { bubbles: true, cancelable: true });
356 var changeEvent = new Event('change', { bubbles: true, cancelable: true });
357
358 // Dispatch events on the actual DOM element (not jQuery)
359 textarea[0].dispatchEvent(inputEvent);
360 textarea[0].dispatchEvent(changeEvent);
361
362 // Also trigger jQuery events as backup
363 textarea.trigger('input').trigger('change');
364
365 console.log('Google Index: File upload triggered change detection');
366 }, 100);
367 } catch (err) {
368 alert('Invalid JSON file selected.');
369 }
370 };
371 reader.readAsText(file);
372 } else {
373 // File upload indicates change even if not JSON (works on both Settings and Indexation Control pages)
374 $('#metaSyncGeneralSetting, #metaSyncSeoControlsForm').trigger('change');
375 }
376 });
377 }
378
379 // Initialize integration after a small delay to ensure MetaSync is ready
380 setTimeout(integrateWithUnsavedChangesDetection, 100);
381
382 // Handle test connection button
383 $('#google-index-test-connection').on('click', function(e) {
384 e.preventDefault();
385
386 var button = $(this);
387 var resultDiv = $('#google-index-test-results');
388
389 button.prop('disabled', true).text('🔄 Testing...');
390 resultDiv.html('<div class=\"notice notice-info inline\"><p>Testing connection...</p></div>');
391
392 $.ajax({
393 url: ajaxurl,
394 type: 'POST',
395 data: {
396 action: 'google_index_direct_test',
397 nonce: '{$nonce}'
398 },
399 success: function(response) {
400 if (response.success) {
401 var results = response.data.results;
402 var html = '<div class=\"notice notice-success inline\">';
403 html += '<p><strong>�
404 Connection Test Results:</strong></p>';
405 html += '<ul>';
406
407 if (results.token_test) {
408 html += '<li><strong>Token Generation:</strong> ' + (results.token_test.success ? '�
409 Success' : '❌ Failed') + '</li>';
410 html += '<li><strong>Token Cached:</strong> ' + (results.token_test.cached ? '�
411 Yes' : '⚪ No') + '</li>';
412 }
413
414 if (results.credentials_test) {
415 html += '<li><strong>Service Account:</strong> ' + results.credentials_test.client_email + '</li>';
416 html += '<li><strong>Project ID:</strong> ' + results.credentials_test.project_id + '</li>';
417 html += '<li><strong>Private Key:</strong> ' + (results.credentials_test.has_private_key ? '�
418 Present' : '❌ Missing') + '</li>';
419 }
420
421 if (results.homepage_test) {
422 if (results.homepage_test.success) {
423 html += '<li><strong>Homepage Status:</strong> �
424 Success</li>';
425 } else {
426 html += '<li><strong>Homepage Status:</strong> ⚠️ ' + results.homepage_test.error.message + '</li>';
427 if (results.homepage_test.note) {
428 html += '<li><strong>Note:</strong> ' + results.homepage_test.note + '</li>';
429 }
430 }
431 }
432
433 html += '</ul></div>';
434 resultDiv.html(html);
435 } else {
436 resultDiv.html('<div class=\"notice notice-error inline\"><p><strong>❌ Test Failed:</strong> ' + response.data.message + '</p></div>');
437 }
438 },
439 error: function() {
440 resultDiv.html('<div class=\"notice notice-error inline\"><p><strong>❌ Connection Error:</strong> Unable to perform test.</p></div>');
441 },
442 complete: function() {
443 button.prop('disabled', false).text('🧪 Test Connection');
444 }
445 });
446 });
447
448 // Handle clear configuration button
449 $('#google-index-clear-config').on('click', function(e) {
450 e.preventDefault();
451
452 if (!confirm('Are you sure you want to clear the service account configuration?')) {
453 return;
454 }
455
456 // Create hidden input to indicate clear configuration request
457 var input = $('<input>')
458 .attr('type', 'hidden')
459 .attr('name', 'google_index_clear_config')
460 .attr('value', '1');
461
462 // Append to form
463 $('#metaSyncGeneralSetting').append(input);
464
465 // Trigger the form's existing AJAX submission handler
466 $('#metaSyncGeneralSetting').trigger('submit');
467 });
468
469 });
470 ";
471 }
472 }
473
474 // Initialize admin functionality
475 if (is_admin()) {
476 new Google_Index_Admin();
477 }
478