From 5cc6e869bf97cd534122f82ab4001918b3b56166 Mon Sep 17 00:00:00 2001 From: Roberto Guagliardo Date: Mon, 26 Jan 2026 19:25:42 +0000 Subject: [PATCH] Refactor code structure for improved readability and maintainability --- SitiWebUpdater.php | 2 +- groq-ai-product-text.php | 9 - includes/Admin/class-groq-ai-logs-table.php | 29 +- .../Admin/class-groq-ai-settings-page.php | 882 +++++++++++++++++- 4 files changed, 885 insertions(+), 37 deletions(-) diff --git a/SitiWebUpdater.php b/SitiWebUpdater.php index e070288..9f5c1d1 100644 --- a/SitiWebUpdater.php +++ b/SitiWebUpdater.php @@ -33,7 +33,7 @@ class SitiWebUpdater { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } - $this->plugin = get_plugin_data( $this->file ); + $this->plugin = get_plugin_data( $this->file, false, false ); $this->basename = plugin_basename( $this->file ); $this->active = is_plugin_active( $this->basename ); } diff --git a/groq-ai-product-text.php b/groq-ai-product-text.php index 4317902..0dce58b 100644 --- a/groq-ai-product-text.php +++ b/groq-ai-product-text.php @@ -108,7 +108,6 @@ final class Groq_AI_Product_Text_Plugin { $this->settings_page = new Groq_AI_Product_Text_Settings_Page( $this, $this->get_provider_manager() ); $this->product_ui = new Groq_AI_Product_Text_Product_UI( $this ); - add_action( 'plugins_loaded', [ $this, 'maybe_load_textdomain_early' ], 0 ); add_action( 'init', [ $this, 'load_textdomain' ] ); add_action( 'plugins_loaded', [ $this, 'maybe_create_logs_table' ] ); add_action( 'load-plugins.php', [ $this, 'maybe_deactivate_if_woocommerce_missing' ] ); @@ -131,14 +130,6 @@ final class Groq_AI_Product_Text_Plugin { $this->textdomain_loaded = true; } - public function maybe_load_textdomain_early() { - if ( did_action( 'init' ) ) { - return; - } - - $this->load_textdomain(); - } - private function register_services() { $this->container = new Groq_AI_Service_Container(); diff --git a/includes/Admin/class-groq-ai-logs-table.php b/includes/Admin/class-groq-ai-logs-table.php index cccfc74..b232027 100644 --- a/includes/Admin/class-groq-ai-logs-table.php +++ b/includes/Admin/class-groq-ai-logs-table.php @@ -136,28 +136,15 @@ class Groq_AI_Logs_Table extends WP_List_Table { protected function column_created_at( $item ) { $date = esc_html( mysql2date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $item['created_at'] ) ); - $usage = $this->get_usage_meta( $item ); - $payload = [ - 'created_at' => $item['created_at'], - 'user' => $this->column_default( $item, 'user_id' ), - 'post_title' => $item['post_title'], - 'provider' => $item['provider'], - 'model' => $item['model'], - 'status' => $item['status'], - 'tokens_prompt' => isset( $item['tokens_prompt'] ) ? (int) $item['tokens_prompt'] : null, - 'tokens_completion' => isset( $item['tokens_completion'] ) ? (int) $item['tokens_completion'] : null, - 'tokens_total' => isset( $item['tokens_total'] ) ? (int) $item['tokens_total'] : null, - 'prompt' => $item['prompt'], - 'response' => $item['response'], - 'error_message' => $item['error_message'], - 'image_context' => isset( $usage['image_context'] ) ? $usage['image_context'] : null, - ]; - $encoded = esc_attr( wp_json_encode( $payload ) ); - return sprintf( - '%s', - $encoded, - $date + $url = add_query_arg( + [ + 'page' => 'groq-ai-product-text-log', + 'log_id' => isset( $item['id'] ) ? (int) $item['id'] : 0, + ], + admin_url( 'options-general.php' ) ); + + return sprintf( '%s', esc_url( $url ), $date ); } private function get_usage_meta( $item ) { diff --git a/includes/Admin/class-groq-ai-settings-page.php b/includes/Admin/class-groq-ai-settings-page.php index 11792e7..c7e6b6e 100644 --- a/includes/Admin/class-groq-ai-settings-page.php +++ b/includes/Admin/class-groq-ai-settings-page.php @@ -84,6 +84,311 @@ class Groq_AI_Product_Text_Settings_Page { [ $this, 'render_prompt_settings_page' ] ); + add_submenu_page( + 'options-general.php', + __( 'Siti AI Log detail', GROQ_AI_PRODUCT_TEXT_DOMAIN ), + __( 'Siti AI Log detail', GROQ_AI_PRODUCT_TEXT_DOMAIN ), + 'manage_options', + 'groq-ai-product-text-log', + [ $this, 'render_log_detail_page' ] + ); + + } + private function get_page_url( $slug = 'groq-ai-product-text', $args = [] ) { + $slug = sanitize_key( (string) $slug ); + $url = add_query_arg( + [ + 'page' => $slug, + ], + admin_url( 'options-general.php' ) + ); + + if ( ! empty( $args ) ) { + $url = add_query_arg( $args, $url ); + } + + return $url; + } + + private function get_request_redirect_url( $field, $page_slug = 'groq-ai-product-text' ) { + $default = $this->get_page_url( $page_slug ); + $value = isset( $_REQUEST[ $field ] ) ? wp_unslash( $_REQUEST[ $field ] ) : ''; + + if ( '' === $value ) { + return $default; + } + + return wp_validate_redirect( $value, $default ); + } + + private function parse_oauth_state( $value ) { + $value = (string) $value; + if ( '' === $value ) { + return []; + } + + $decoded = base64_decode( $value, true ); + if ( ! is_string( $decoded ) || '' === $decoded ) { + return []; + } + + $data = json_decode( $decoded, true ); + + return is_array( $data ) ? $data : []; + } + + private function redirect_with_google_notice( $type, $message = '', $redirect = null, $status = 'success' ) { + $redirect = $redirect ? $redirect : $this->get_page_url(); + $args = [ + 'groq_ai_google_notice' => sanitize_key( (string) $type ), + 'groq_ai_google_notice_status' => sanitize_key( (string) $status ), + ]; + if ( '' !== $message ) { + $args['groq_ai_google_notice_message'] = rawurlencode( (string) $message ); + } + + wp_safe_redirect( add_query_arg( $args, $redirect ) ); + exit; + } + + private function redirect_with_term_notice( $taxonomy, $term_id, $type, $message = '', $status = 'success' ) { + $url = ( $taxonomy && $term_id ) ? $this->get_term_page_url( $taxonomy, $term_id ) : $this->get_page_url( 'groq-ai-product-text-categories' ); + + $args = [ + 'groq_ai_term_notice' => sanitize_key( (string) $type ), + 'groq_ai_term_status' => sanitize_key( (string) $status ), + ]; + + if ( '' !== $message ) { + $args['groq_ai_term_notice_message'] = rawurlencode( (string) $message ); + } + + wp_safe_redirect( add_query_arg( $args, $url ) ); + exit; + } + + private function get_google_redirect_uri() { + return add_query_arg( + 'action', + 'groq_ai_google_oauth_callback', + admin_url( 'admin-post.php' ) + ); + } + + private function update_settings_partial( array $updates ) { + $option_key = $this->plugin->get_option_key(); + $current = get_option( $option_key, [] ); + + if ( ! is_array( $current ) ) { + $current = []; + } + + foreach ( $updates as $key => $value ) { + $current[ $key ] = $value; + } + + update_option( $option_key, $current ); + } + + public function render_settings_page() { + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + + $option_key = $this->plugin->get_option_key(); + $settings = $this->plugin->get_settings(); + $providers = $this->provider_manager->get_providers(); + $current_page = $this->get_page_url(); + $prompt_url = $this->get_page_url( 'groq-ai-product-text-prompts' ); + $modules_url = $this->get_page_url( 'groq-ai-product-text-modules' ); + $logs_url = $this->get_page_url( 'groq-ai-product-text-logs' ); + $categories_url = $this->get_page_url( 'groq-ai-product-text-categories' ); + $brands_url = $this->get_page_url( 'groq-ai-product-text-brands' ); + + $prompt_preview = $this->plugin->build_prompt_template_preview( $settings ); + $google_notice = isset( $_GET['groq_ai_google_notice'] ) ? sanitize_key( wp_unslash( $_GET['groq_ai_google_notice'] ) ) : ''; + $google_status = isset( $_GET['groq_ai_google_notice_status'] ) ? sanitize_key( wp_unslash( $_GET['groq_ai_google_notice_status'] ) ) : ''; + $google_message = ''; + if ( isset( $_GET['groq_ai_google_notice_message'] ) ) { + $google_message = sanitize_text_field( rawurldecode( wp_unslash( $_GET['groq_ai_google_notice_message'] ) ) ); + } + + $google_connected = ! empty( $settings['google_oauth_refresh_token'] ); + $google_connected_email = isset( $settings['google_oauth_connected_email'] ) ? (string) $settings['google_oauth_connected_email'] : ''; + $google_connected_at = isset( $settings['google_oauth_connected_at'] ) ? absint( $settings['google_oauth_connected_at'] ) : 0; + + ?> +
+

+

+ +

+

+ + + + + +

+ + +

+ +
+ +
+
+
+ +

+ + + + + + + + + + get_key(); + $option_field = $provider->get_option_key(); + $value = isset( $settings[ $option_field ] ) ? (string) $settings[ $option_field ] : ''; + ?> + + + + + + +

+ + + + + + + + + + + + + + +

+ + + + + + + + + + + + + + + + + + +

+
+
+

+

+ +

+
+
+ + + + +
+ +
+ + + + +
+
+ + + + +
+ +
+
+
+ @@ -425,6 +731,239 @@ class Groq_AI_Product_Text_Settings_Page { plugin->get_option_key(); + ?> +
+

+

+ +
+ + + + + + + + +
+
+ plugin ); + $logs_table->prepare_items(); + ?> +
+

+
+ + search_box( __( 'Zoek logboek', GROQ_AI_PRODUCT_TEXT_DOMAIN ), 'groq-ai-logs' ); ?> + display(); ?> +
+
+ get_page_url( 'groq-ai-product-text-logs' ); + $log = null; + + if ( $log_id ) { + global $wpdb; + $table = $wpdb->prefix . 'groq_ai_generation_logs'; + $query = $wpdb->prepare( + "SELECT l.*, p.post_title FROM {$table} l LEFT JOIN {$wpdb->posts} p ON p.ID = l.post_id WHERE l.id = %d", + $log_id + ); + $log = $wpdb->get_row( $query, ARRAY_A ); + } + + ?> +
+

+

+ +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ display_name ) : esc_html( (string) $log['user_id'] ); + } else { + echo '—'; + } + ?> +
+ ' . esc_html( $title ) . '' : esc_html( $title ); + } else { + echo '—'; + } + ?> +
+ +
+ +

+
+ +

+
+ +
+ plugin->get_option_key(); + $settings = $this->plugin->get_settings(); + $definitions = $this->plugin->get_context_field_definitions(); + $context_vals = isset( $settings['context_fields'] ) ? (array) $settings['context_fields'] : $this->plugin->get_default_context_fields(); + $image_mode = $this->plugin->get_image_context_mode( $settings ); + $image_limit = $this->plugin->get_image_context_limit( $settings ); + $preview = $this->plugin->build_prompt_template_preview( $settings ); + + ?> +
+

+

+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ count_words( $term->description ); $meta_prompt = get_term_meta( $term_id, 'groq_ai_term_custom_prompt', true ); @@ -478,6 +1031,12 @@ class Groq_AI_Product_Text_Settings_Page {

: name ); ?>

+ + +
+

+
+

plugin->get_settings(); $values = isset( $settings['product_attribute_includes'] ) && is_array( $settings['product_attribute_includes'] ) @@ -815,14 +1376,25 @@ class Groq_AI_Product_Text_Settings_Page { } public function enqueue_settings_assets( $hook ) { - if ( ! in_array( $hook, [ + $allowed_hooks = [ 'settings_page_groq-ai-product-text', 'settings_page_groq-ai-product-text-modules', 'settings_page_groq-ai-product-text-prompts', 'settings_page_groq-ai-product-text-categories', 'settings_page_groq-ai-product-text-brands', 'settings_page_groq-ai-product-text-term', - ], true ) ) { + 'settings_page_groq-ai-product-text-logs', + ]; + + $matches_hook = false; + foreach ( $allowed_hooks as $allowed ) { + if ( 0 === strpos( (string) $hook, $allowed ) ) { + $matches_hook = true; + break; + } + } + + if ( ! $matches_hook ) { return; } @@ -848,7 +1420,9 @@ class Groq_AI_Product_Text_Settings_Page { true ); - if ( 'settings_page_groq-ai-product-text-term' === $hook ) { + $current_page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; + + if ( 0 === strpos( (string) $hook, 'settings_page_groq-ai-product-text-term' ) ) { wp_enqueue_script( 'groq-ai-term-admin', plugins_url( 'assets/js/term-admin.js', GROQ_AI_PRODUCT_TEXT_FILE ), @@ -875,7 +1449,7 @@ class Groq_AI_Product_Text_Settings_Page { $bulk_allow_regen = false; $bulk_strings = []; - if ( 'settings_page_groq-ai-product-text-categories' === $hook ) { + if ( 0 === strpos( (string) $hook, 'settings_page_groq-ai-product-text-categories' ) ) { $bulk_taxonomy = 'product_cat'; $bulk_strings = [ 'statusIdle' => __( 'Bulk gestart. AI werkt de geselecteerde categorieën bij…', GROQ_AI_PRODUCT_TEXT_DOMAIN ), @@ -887,7 +1461,7 @@ class Groq_AI_Product_Text_Settings_Page { 'logError' => __( '%1$s mislukt: %2$s', GROQ_AI_PRODUCT_TEXT_DOMAIN ), 'confirmStop' => __( 'Weet je zeker dat je wilt stoppen? De huidige categorie kan onafgemaakt blijven.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), ]; - } elseif ( 'settings_page_groq-ai-product-text-brands' === $hook ) { + } elseif ( 0 === strpos( (string) $hook, 'settings_page_groq-ai-product-text-brands' ) ) { $detected_taxonomy = $this->detect_brand_taxonomy(); if ( '' !== $detected_taxonomy ) { $bulk_taxonomy = $detected_taxonomy; @@ -957,4 +1531,300 @@ class Groq_AI_Product_Text_Settings_Page { wp_localize_script( 'groq-ai-settings', 'GroqAISettingsData', $data ); } + + public function handle_google_oauth_start() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( esc_html__( 'Je hebt geen toestemming om deze actie uit te voeren.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), '', [ 'response' => 403 ] ); + } + + check_admin_referer( 'groq_ai_google_oauth' ); + + $redirect = $this->get_request_redirect_url( 'redirect_to' ); + $settings = $this->plugin->get_settings(); + + $client_id = isset( $settings['google_oauth_client_id'] ) ? trim( (string) $settings['google_oauth_client_id'] ) : ''; + $client_secret = isset( $settings['google_oauth_client_secret'] ) ? trim( (string) $settings['google_oauth_client_secret'] ) : ''; + + if ( '' === $client_id || '' === $client_secret ) { + $this->redirect_with_google_notice( 'error', __( 'Vul eerst het Google client ID en secret in en sla de instellingen op.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $redirect, 'error' ); + } + + $state_payload = [ + 'nonce' => wp_create_nonce( 'groq_ai_google_oauth_state' ), + 'redirect' => $redirect, + 'timestamp' => time(), + ]; + + $state_json = wp_json_encode( $state_payload ); + if ( ! is_string( $state_json ) ) { + $state_json = wp_json_encode( (object) [] ); + } + $state = base64_encode( (string) $state_json ); + + $scopes = [ + 'https://www.googleapis.com/auth/webmasters.readonly', + 'https://www.googleapis.com/auth/analytics.readonly', + 'https://www.googleapis.com/auth/userinfo.email', + ]; + + $auth_url = add_query_arg( + [ + 'response_type' => 'code', + 'client_id' => $client_id, + 'redirect_uri' => $this->get_google_redirect_uri(), + 'scope' => implode( ' ', $scopes ), + 'access_type' => 'offline', + 'prompt' => 'consent', + 'include_granted_scopes' => 'true', + 'state' => $state, + ], + 'https://accounts.google.com/o/oauth2/v2/auth' + ); + + wp_safe_redirect( $auth_url ); + exit; + } + + public function handle_google_oauth_callback() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( esc_html__( 'Je hebt geen toestemming om deze actie uit te voeren.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), '', [ 'response' => 403 ] ); + } + + $state_value = isset( $_GET['state'] ) ? wp_unslash( $_GET['state'] ) : ''; + $state = $this->parse_oauth_state( $state_value ); + $redirect = isset( $state['redirect'] ) ? wp_validate_redirect( (string) $state['redirect'], $this->get_page_url() ) : $this->get_page_url(); + + if ( isset( $_GET['error'] ) ) { + $error_message = sanitize_text_field( wp_unslash( $_GET['error'] ) ); + if ( isset( $_GET['error_description'] ) ) { + $error_message .= ': ' . sanitize_text_field( wp_unslash( $_GET['error_description'] ) ); + } + $this->redirect_with_google_notice( 'error', $error_message, $redirect, 'error' ); + } + + if ( isset( $state['nonce'] ) && ! wp_verify_nonce( $state['nonce'], 'groq_ai_google_oauth_state' ) ) { + $this->redirect_with_google_notice( 'error', __( 'Ongeldige OAuth-sessie. Probeer het opnieuw.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $redirect, 'error' ); + } + + $timestamp = isset( $state['timestamp'] ) ? absint( $state['timestamp'] ) : 0; + if ( $timestamp && ( time() - $timestamp ) > HOUR_IN_SECONDS ) { + $this->redirect_with_google_notice( 'error', __( 'OAuth-sessie verlopen. Probeer het opnieuw.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $redirect, 'error' ); + } + + $code = isset( $_GET['code'] ) ? sanitize_text_field( wp_unslash( $_GET['code'] ) ) : ''; + if ( '' === $code ) { + $this->redirect_with_google_notice( 'error', __( 'Geen autorisatiecode ontvangen.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $redirect, 'error' ); + } + + $settings = $this->plugin->get_settings(); + $client_id = isset( $settings['google_oauth_client_id'] ) ? trim( (string) $settings['google_oauth_client_id'] ) : ''; + $client_secret = isset( $settings['google_oauth_client_secret'] ) ? trim( (string) $settings['google_oauth_client_secret'] ) : ''; + + if ( '' === $client_id || '' === $client_secret ) { + $this->redirect_with_google_notice( 'error', __( 'Google client ID en secret ontbreken.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $redirect, 'error' ); + } + + $response = wp_remote_post( + 'https://oauth2.googleapis.com/token', + [ + 'timeout' => 20, + 'body' => [ + 'code' => $code, + 'client_id' => $client_id, + 'client_secret' => $client_secret, + 'redirect_uri' => $this->get_google_redirect_uri(), + 'grant_type' => 'authorization_code', + ], + ] + ); + + if ( is_wp_error( $response ) ) { + $this->redirect_with_google_notice( 'error', $response->get_error_message(), $redirect, 'error' ); + } + + $status_code = wp_remote_retrieve_response_code( $response ); + $body = wp_remote_retrieve_body( $response ); + $data = json_decode( (string) $body, true ); + + if ( 200 !== $status_code || ! is_array( $data ) ) { + $this->redirect_with_google_notice( 'error', __( 'Kon tokens niet ophalen bij Google.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $redirect, 'error' ); + } + + $access_token = isset( $data['access_token'] ) ? trim( (string) $data['access_token'] ) : ''; + $refresh_token = isset( $data['refresh_token'] ) ? trim( (string) $data['refresh_token'] ) : ''; + + if ( '' === $refresh_token ) { + $existing = isset( $settings['google_oauth_refresh_token'] ) ? (string) $settings['google_oauth_refresh_token'] : ''; + $refresh_token = $existing; + } + + if ( '' === $refresh_token ) { + $this->redirect_with_google_notice( 'error', __( 'Google retourneerde geen refresh token. Forceer toestemming opnieuw en probeer het nogmaals.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $redirect, 'error' ); + } + + if ( '' === $access_token ) { + $this->redirect_with_google_notice( 'error', __( 'Google retourneerde geen access token.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $redirect, 'error' ); + } + + $email = ''; + $userinfo = wp_remote_get( + 'https://openidconnect.googleapis.com/v1/userinfo', + [ + 'timeout' => 15, + 'headers' => [ + 'Authorization' => 'Bearer ' . $access_token, + ], + ] + ); + + if ( ! is_wp_error( $userinfo ) ) { + $userinfo_code = wp_remote_retrieve_response_code( $userinfo ); + $userinfo_body = json_decode( wp_remote_retrieve_body( $userinfo ), true ); + if ( 200 === $userinfo_code && is_array( $userinfo_body ) && isset( $userinfo_body['email'] ) ) { + $email = sanitize_email( (string) $userinfo_body['email'] ); + } + } + + $this->update_settings_partial( + [ + 'google_oauth_refresh_token' => sanitize_text_field( $refresh_token ), + 'google_oauth_connected_email' => $email, + 'google_oauth_connected_at' => current_time( 'timestamp' ), + ] + ); + + $this->redirect_with_google_notice( 'connected', __( 'Google OAuth is verbonden.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $redirect ); + } + + public function handle_google_oauth_disconnect() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( esc_html__( 'Je hebt geen toestemming om deze actie uit te voeren.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), '', [ 'response' => 403 ] ); + } + + check_admin_referer( 'groq_ai_google_disconnect' ); + + $redirect = $this->get_request_redirect_url( 'redirect_to' ); + + $this->update_settings_partial( + [ + 'google_oauth_refresh_token' => '', + 'google_oauth_connected_email' => '', + 'google_oauth_connected_at' => 0, + ] + ); + + $this->redirect_with_google_notice( 'disconnected', __( 'Google OAuth is ontkoppeld.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $redirect ); + } + + public function handle_google_test_connection() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( esc_html__( 'Je hebt geen toestemming om deze actie uit te voeren.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), '', [ 'response' => 403 ] ); + } + + check_admin_referer( 'groq_ai_google_test_connection' ); + + $redirect = $this->get_request_redirect_url( 'redirect_to' ); + $settings = $this->plugin->get_settings(); + + $oauth_client = new Groq_AI_Google_OAuth_Client(); + $token = $oauth_client->get_access_token( $settings ); + + if ( is_wp_error( $token ) ) { + $this->redirect_with_google_notice( 'test', $token->get_error_message(), $redirect, 'error' ); + } + + $messages = [ __( 'OAuth token opgehaald.', GROQ_AI_PRODUCT_TEXT_DOMAIN ) ]; + + $token_info = $oauth_client->get_access_token_info( $token ); + if ( ! is_wp_error( $token_info ) && ! empty( $token_info['scope'] ) ) { + $messages[] = sprintf( __( 'Scopes: %s', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $token_info['scope'] ); + } + + if ( ! empty( $settings['google_enable_gsc'] ) && ! empty( $settings['google_gsc_site_url'] ) ) { + $gsc_client = new Groq_AI_Google_Search_Console_Client( $oauth_client ); + $result = $gsc_client->list_sites( $settings ); + if ( is_wp_error( $result ) ) { + $this->redirect_with_google_notice( 'test', $result->get_error_message(), $redirect, 'error' ); + } + $messages[] = __( 'Search Console API bereikbaar.', GROQ_AI_PRODUCT_TEXT_DOMAIN ); + } + + if ( ! empty( $settings['google_enable_ga'] ) && ! empty( $settings['google_ga4_property_id'] ) ) { + $ga_client = new Groq_AI_Google_Analytics_Data_Client( $oauth_client ); + $end_date = gmdate( 'Y-m-d' ); + $start_date = gmdate( 'Y-m-d', time() - ( 7 * DAY_IN_SECONDS ) ); + $summary = $ga_client->get_property_sessions_summary( $settings, $settings['google_ga4_property_id'], $start_date, $end_date ); + if ( is_wp_error( $summary ) ) { + $this->redirect_with_google_notice( 'test', $summary->get_error_message(), $redirect, 'error' ); + } + $sessions = isset( $summary['sessions'] ) ? absint( $summary['sessions'] ) : 0; + $messages[] = sprintf( __( 'GA4 API bereikbaar (sessies laatste 7 dagen: %d).', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $sessions ); + } + + $this->redirect_with_google_notice( 'test', implode( ' ', $messages ), $redirect ); + } + + public function handle_save_term_content() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( esc_html__( 'Je hebt geen toestemming om deze actie uit te voeren.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), '', [ 'response' => 403 ] ); + } + + check_admin_referer( 'groq_ai_save_term_content' ); + + $taxonomy = isset( $_POST['taxonomy'] ) ? sanitize_key( wp_unslash( $_POST['taxonomy'] ) ) : ''; + $term_id = isset( $_POST['term_id'] ) ? absint( $_POST['term_id'] ) : 0; + + if ( '' === $taxonomy || ! taxonomy_exists( $taxonomy ) || ! $term_id ) { + $this->redirect_with_term_notice( $taxonomy, $term_id, 'error', __( 'Ongeldige term.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), 'error' ); + } + + $term = get_term( $term_id, $taxonomy ); + if ( ! $term || is_wp_error( $term ) ) { + $this->redirect_with_term_notice( $taxonomy, $term_id, 'error', __( 'Term niet gevonden.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), 'error' ); + } + + $description = isset( $_POST['description'] ) ? wp_kses_post( wp_unslash( $_POST['description'] ) ) : ''; + $bottom_description = isset( $_POST['groq_ai_term_bottom_description'] ) ? wp_kses_post( wp_unslash( $_POST['groq_ai_term_bottom_description'] ) ) : ''; + $custom_prompt = isset( $_POST['groq_ai_term_custom_prompt'] ) ? sanitize_textarea_field( wp_unslash( $_POST['groq_ai_term_custom_prompt'] ) ) : ''; + + $update = wp_update_term( + $term_id, + $taxonomy, + [ + 'description' => $description, + ] + ); + + if ( is_wp_error( $update ) ) { + $this->redirect_with_term_notice( $taxonomy, $term_id, 'error', $update->get_error_message(), 'error' ); + } + + $settings = $this->plugin->get_settings(); + $bottom_meta_key = $this->resolve_term_bottom_description_meta_key( $term, $settings ); + $bottom_meta_key = '' !== $bottom_meta_key ? $bottom_meta_key : 'groq_ai_term_bottom_description'; + update_term_meta( $term_id, $bottom_meta_key, $bottom_description ); + + if ( '' === trim( $custom_prompt ) ) { + delete_term_meta( $term_id, 'groq_ai_term_custom_prompt' ); + } else { + update_term_meta( $term_id, 'groq_ai_term_custom_prompt', $custom_prompt ); + } + + if ( isset( $_POST['groq_ai_term_bottom_description'] ) && $bottom_meta_key !== 'groq_ai_term_bottom_description' ) { + update_term_meta( $term_id, 'groq_ai_term_bottom_description', $bottom_description ); + } + + if ( $this->plugin->is_module_enabled( 'rankmath', $settings ) ) { + $rankmath_keys = $this->resolve_rankmath_term_meta_keys( $term, $settings ); + $rankmath_title = isset( $_POST['groq_ai_rankmath_meta_title'] ) ? sanitize_text_field( wp_unslash( $_POST['groq_ai_rankmath_meta_title'] ) ) : ''; + $rankmath_description = isset( $_POST['groq_ai_rankmath_meta_description'] ) ? sanitize_textarea_field( wp_unslash( $_POST['groq_ai_rankmath_meta_description'] ) ) : ''; + $rankmath_keywords = isset( $_POST['groq_ai_rankmath_focus_keywords'] ) ? sanitize_text_field( wp_unslash( $_POST['groq_ai_rankmath_focus_keywords'] ) ) : ''; + + update_term_meta( $term_id, $rankmath_keys['title'], $rankmath_title ); + update_term_meta( $term_id, $rankmath_keys['description'], $rankmath_description ); + update_term_meta( $term_id, $rankmath_keys['focus_keyword'], $rankmath_keywords ); + } + + $this->redirect_with_term_notice( $taxonomy, $term_id, 'saved', __( 'Term opgeslagen.', GROQ_AI_PRODUCT_TEXT_DOMAIN ) ); + } }