plugin = $plugin; $this->provider_manager = $provider_manager; add_action( 'admin_menu', [ $this, 'register_settings_pages' ] ); add_action( 'admin_init', [ $this, 'register_settings' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_settings_assets' ] ); add_action( 'admin_head', [ $this, 'hide_menu_links' ] ); add_action( 'admin_post_groq_ai_google_oauth_start', [ $this, 'handle_google_oauth_start' ] ); add_action( 'admin_post_groq_ai_google_oauth_callback', [ $this, 'handle_google_oauth_callback' ] ); add_action( 'admin_post_groq_ai_google_oauth_disconnect', [ $this, 'handle_google_oauth_disconnect' ] ); add_action( 'admin_post_groq_ai_save_term_content', [ $this, 'handle_save_term_content' ] ); add_action( 'admin_post_groq_ai_google_test_connection', [ $this, 'handle_google_test_connection' ] ); } public function register_settings_pages() { add_options_page( __( 'Siti AI Productteksten', GROQ_AI_PRODUCT_TEXT_DOMAIN ), __( 'Siti AI', GROQ_AI_PRODUCT_TEXT_DOMAIN ), 'manage_options', 'groq-ai-product-text', [ $this, 'render_settings_page' ] ); add_submenu_page( 'options-general.php', __( 'Siti AI Categorie teksten', GROQ_AI_PRODUCT_TEXT_DOMAIN ), __( 'Siti AI Categorieën', GROQ_AI_PRODUCT_TEXT_DOMAIN ), 'manage_options', 'groq-ai-product-text-categories', [ $this, 'render_categories_overview_page' ] ); add_submenu_page( 'options-general.php', __( 'Siti AI Merk teksten', GROQ_AI_PRODUCT_TEXT_DOMAIN ), __( 'Siti AI Merken', GROQ_AI_PRODUCT_TEXT_DOMAIN ), 'manage_options', 'groq-ai-product-text-brands', [ $this, 'render_brands_overview_page' ] ); add_submenu_page( 'options-general.php', __( 'Siti AI Term tekst', GROQ_AI_PRODUCT_TEXT_DOMAIN ), __( 'Siti AI Term tekst', GROQ_AI_PRODUCT_TEXT_DOMAIN ), 'manage_options', 'groq-ai-product-text-term', [ $this, 'render_term_generator_page' ] ); add_submenu_page( 'options-general.php', __( 'Siti AI Modules', GROQ_AI_PRODUCT_TEXT_DOMAIN ), __( 'Siti AI Modules', GROQ_AI_PRODUCT_TEXT_DOMAIN ), 'manage_options', 'groq-ai-product-text-modules', [ $this, 'render_modules_page' ] ); add_submenu_page( 'options-general.php', __( 'Siti AI AI-logboek', GROQ_AI_PRODUCT_TEXT_DOMAIN ), __( 'Siti AI AI-logboek', GROQ_AI_PRODUCT_TEXT_DOMAIN ), 'manage_options', 'groq-ai-product-text-logs', [ $this, 'render_logs_page' ] ); add_submenu_page( 'options-general.php', __( 'Siti AI Prompt instellingen', GROQ_AI_PRODUCT_TEXT_DOMAIN ), __( 'Siti AI Prompt instellingen', GROQ_AI_PRODUCT_TEXT_DOMAIN ), 'manage_options', 'groq-ai-product-text-prompts', [ $this, 'render_prompt_settings_page' ] ); } public function hide_menu_links() { if ( ! current_user_can( 'manage_options' ) ) { return; } ?> brand_taxonomy ) { return $this->brand_taxonomy; } $candidates = [ 'product_brand', 'pwb-brand', 'yith_product_brand', 'berocket_brand', ]; // Attribute-taxonomy fallback (vaak pa_brand). if ( taxonomy_exists( 'pa_brand' ) ) { array_unshift( $candidates, 'pa_brand' ); } $candidates = apply_filters( 'groq_ai_brand_taxonomy_candidates', $candidates ); $found = ''; foreach ( $candidates as $tax ) { $tax = sanitize_key( (string) $tax ); if ( $tax && taxonomy_exists( $tax ) ) { $found = $tax; break; } } $found = apply_filters( 'groq_ai_brand_taxonomy', $found ); $this->brand_taxonomy = sanitize_key( (string) $found ); return $this->brand_taxonomy; } private function get_term_page_url( $taxonomy, $term_id ) { return add_query_arg( [ 'page' => 'groq-ai-product-text-term', 'taxonomy' => sanitize_key( (string) $taxonomy ), 'term_id' => absint( $term_id ), ], admin_url( 'options-general.php' ) ); } public function render_categories_overview_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } $terms = get_terms( [ 'taxonomy' => 'product_cat', 'hide_empty' => false, 'number' => 0, ] ); if ( is_wp_error( $terms ) ) { $terms = []; } ?>
| name ); ?> | slug ); ?> | ||
| name ); ?> | slug ); ?> | ||
-tags. Voeg geen prijsinformatie toe.', GROQ_AI_PRODUCT_TEXT_DOMAIN ); } ?>
plugin->get_settings(); $limit = $this->plugin->get_image_context_limit( $settings ); ?>
plugin->get_settings(); ?>
plugin->get_settings(); $value = isset( $settings['google_oauth_client_secret'] ) ? $settings['google_oauth_client_secret'] : ''; ?>
plugin->get_settings(); $connected = ! empty( $settings['google_oauth_refresh_token'] ); $email = isset( $settings['google_oauth_connected_email'] ) ? $settings['google_oauth_connected_email'] : ''; $connected_at = isset( $settings['google_oauth_connected_at'] ) ? absint( $settings['google_oauth_connected_at'] ) : 0; $redirect_uri = $this->get_google_oauth_redirect_uri(); $start_url = wp_nonce_url( admin_url( 'admin-post.php?action=groq_ai_google_oauth_start' ), 'groq_ai_google_oauth_start', '_wpnonce' ); $disconnect_url = wp_nonce_url( admin_url( 'admin-post.php?action=groq_ai_google_oauth_disconnect' ), 'groq_ai_google_oauth_disconnect', '_wpnonce' ); ?>
— ()
plugin->get_settings(); $messages = []; $status = 'success'; $oauth = new Groq_AI_Google_OAuth_Client(); $token = $oauth->get_access_token( $settings ); if ( is_wp_error( $token ) ) { $status = 'error'; $messages[] = sprintf( __( 'OAuth: %s', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $token->get_error_message() ); } else { $messages[] = __( 'OAuth: OK (access token opgehaald).', GROQ_AI_PRODUCT_TEXT_DOMAIN ); $info = $oauth->get_access_token_info( $token ); if ( is_array( $info ) ) { $scope = isset( $info['scope'] ) ? trim( (string) $info['scope'] ) : ''; if ( '' !== $scope ) { $messages[] = sprintf( __( 'OAuth scopes: %s', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $scope ); if ( false === strpos( $scope, 'https://www.googleapis.com/auth/webmasters' ) ) { $messages[] = __( 'Tip: je access token mist Search Console scope. Klik op "Opnieuw verbinden" zodat je toestemming opnieuw wordt gevraagd.', GROQ_AI_PRODUCT_TEXT_DOMAIN ); } } } } $range_days = 7; $end_date = gmdate( 'Y-m-d' ); $start_date = gmdate( 'Y-m-d', time() - ( $range_days * DAY_IN_SECONDS ) ); if ( 'error' !== $status && ! empty( $settings['google_enable_gsc'] ) ) { $gsc = new Groq_AI_Google_Search_Console_Client( $oauth ); $sites = $gsc->list_sites( $settings ); if ( is_wp_error( $sites ) ) { $status = 'error'; $messages[] = sprintf( __( 'Search Console: %s', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $sites->get_error_message() ); } else { $count = is_array( $sites ) ? count( $sites ) : 0; $messages[] = sprintf( __( 'Search Console: OK (%d properties zichtbaar).', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $count ); $site_url = isset( $settings['google_gsc_site_url'] ) ? trim( (string) $settings['google_gsc_site_url'] ) : ''; if ( '' !== $site_url && is_array( $sites ) && ! in_array( $site_url, $sites, true ) ) { $messages[] = __( 'Let op: de ingestelde site URL is niet gevonden in jouw zichtbare GSC properties.', GROQ_AI_PRODUCT_TEXT_DOMAIN ); } } } if ( 'error' !== $status && ! empty( $settings['google_enable_ga'] ) ) { $property_id = isset( $settings['google_ga4_property_id'] ) ? trim( (string) $settings['google_ga4_property_id'] ) : ''; if ( '' !== $property_id ) { $ga = new Groq_AI_Google_Analytics_Data_Client( $oauth ); $stats = $ga->get_property_sessions_summary( $settings, $property_id, $start_date, $end_date ); if ( is_wp_error( $stats ) ) { $status = 'error'; $messages[] = sprintf( __( 'Analytics: %s', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $stats->get_error_message() ); } else { $sessions = isset( $stats['sessions'] ) ? absint( $stats['sessions'] ) : 0; $messages[] = sprintf( __( 'Analytics: OK (sessies laatste %1$d dagen: ~%2$d).', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $range_days, $sessions ); } } else { $messages[] = __( 'Analytics: overgeslagen (GA4 property ID niet ingevuld).', GROQ_AI_PRODUCT_TEXT_DOMAIN ); } } $url = add_query_arg( [ 'groq_ai_google_oauth' => $status, 'groq_ai_google_oauth_message' => implode( ' ', $messages ), ], $this->get_settings_page_url() ); wp_safe_redirect( $url ); exit; } public function render_google_gsc_site_url_field() { $settings = $this->plugin->get_settings(); $value = isset( $settings['google_gsc_site_url'] ) ? (string) $settings['google_gsc_site_url'] : ''; ?>
plugin->get_settings(); $value = isset( $settings['google_ga4_property_id'] ) ? (string) $settings['google_ga4_property_id'] : ''; ?>
plugin->get_settings(); $gsc = ! empty( $settings['google_enable_gsc'] ); $ga = ! empty( $settings['google_enable_ga'] ); ?> 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 ) { $url = add_query_arg( [ 'groq_ai_google_oauth' => 'error', 'groq_ai_google_oauth_message' => __( 'Vul eerst Google Client ID en Client secret in.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), ], $this->get_settings_page_url() ); wp_safe_redirect( $url ); exit; } $state = wp_generate_password( 32, false, false ); set_transient( $this->get_google_oauth_state_key(), $state, 10 * MINUTE_IN_SECONDS ); $scope = implode( ' ', $this->get_google_oauth_scopes() ); $redirect_uri = $this->get_google_oauth_redirect_uri(); $auth_url = add_query_arg( [ 'client_id' => $client_id, 'redirect_uri' => $redirect_uri, 'response_type' => 'code', 'access_type' => 'offline', 'prompt' => 'consent', 'include_granted_scopes' => 'true', 'scope' => $scope, 'state' => $state, ], 'https://accounts.google.com/o/oauth2/v2/auth' ); $auth_url = esc_url_raw( $auth_url ); $parsed = wp_parse_url( $auth_url ); $host = isset( $parsed['host'] ) ? strtolower( (string) $parsed['host'] ) : ''; if ( 'accounts.google.com' !== $host ) { $url = add_query_arg( [ 'groq_ai_google_oauth' => 'error', 'groq_ai_google_oauth_message' => __( 'OAuth URL ongeldig. Controleer plugin instellingen.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), ], $this->get_settings_page_url() ); wp_safe_redirect( $url ); exit; } // Let op: wp_safe_redirect staat standaard geen externe hosts toe en valt dan terug naar /wp-admin. wp_redirect( $auth_url ); exit; } public function handle_google_oauth_callback() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Geen toestemming.', GROQ_AI_PRODUCT_TEXT_DOMAIN ) ); } $expected_state = get_transient( $this->get_google_oauth_state_key() ); delete_transient( $this->get_google_oauth_state_key() ); $state = isset( $_GET['state'] ) ? sanitize_text_field( wp_unslash( $_GET['state'] ) ) : ''; $code = isset( $_GET['code'] ) ? sanitize_text_field( wp_unslash( $_GET['code'] ) ) : ''; $error = isset( $_GET['error'] ) ? sanitize_text_field( wp_unslash( $_GET['error'] ) ) : ''; if ( '' !== $error ) { $url = add_query_arg( [ 'groq_ai_google_oauth' => 'error', 'groq_ai_google_oauth_message' => sprintf( __( 'Google OAuth error: %s', GROQ_AI_PRODUCT_TEXT_DOMAIN ), $error ), ], $this->get_settings_page_url() ); wp_safe_redirect( $url ); exit; } if ( empty( $expected_state ) || '' === $state || $state !== $expected_state ) { $url = add_query_arg( [ 'groq_ai_google_oauth' => 'error', 'groq_ai_google_oauth_message' => __( 'Ongeldige OAuth state. Probeer opnieuw te verbinden.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), ], $this->get_settings_page_url() ); wp_safe_redirect( $url ); exit; } if ( '' === $code ) { $url = add_query_arg( [ 'groq_ai_google_oauth' => 'error', 'groq_ai_google_oauth_message' => __( 'Geen OAuth code ontvangen.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), ], $this->get_settings_page_url() ); wp_safe_redirect( $url ); exit; } $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'] ) : ''; $redirect_uri = $this->get_google_oauth_redirect_uri(); if ( '' === $client_id || '' === $client_secret ) { $url = add_query_arg( [ 'groq_ai_google_oauth' => 'error', 'groq_ai_google_oauth_message' => __( 'Client ID/secret ontbreken. Sla eerst de instellingen op.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), ], $this->get_settings_page_url() ); wp_safe_redirect( $url ); exit; } $token_response = wp_remote_post( 'https://oauth2.googleapis.com/token', [ 'timeout' => 20, 'headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded', ], 'body' => [ 'code' => $code, 'client_id' => $client_id, 'client_secret' => $client_secret, 'redirect_uri' => $redirect_uri, 'grant_type' => 'authorization_code', ], ] ); if ( is_wp_error( $token_response ) ) { $url = add_query_arg( [ 'groq_ai_google_oauth' => 'error', 'groq_ai_google_oauth_message' => $token_response->get_error_message(), ], $this->get_settings_page_url() ); wp_safe_redirect( $url ); exit; } $status_code = wp_remote_retrieve_response_code( $token_response ); $body = wp_remote_retrieve_body( $token_response ); $data = json_decode( (string) $body, true ); if ( 200 !== $status_code || ! is_array( $data ) ) { $url = add_query_arg( [ 'groq_ai_google_oauth' => 'error', 'groq_ai_google_oauth_message' => __( 'Token exchange mislukt.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), ], $this->get_settings_page_url() ); wp_safe_redirect( $url ); exit; } $access_token = isset( $data['access_token'] ) ? sanitize_text_field( (string) $data['access_token'] ) : ''; $refresh_token = isset( $data['refresh_token'] ) ? sanitize_text_field( (string) $data['refresh_token'] ) : ''; if ( '' === $refresh_token ) { $refresh_token = isset( $settings['google_oauth_refresh_token'] ) ? sanitize_text_field( (string) $settings['google_oauth_refresh_token'] ) : ''; } $connected_email = ''; if ( '' !== $access_token ) { $userinfo_response = wp_remote_get( 'https://openidconnect.googleapis.com/v1/userinfo', [ 'timeout' => 20, 'headers' => [ 'Authorization' => 'Bearer ' . $access_token, ], ] ); if ( ! is_wp_error( $userinfo_response ) && 200 === wp_remote_retrieve_response_code( $userinfo_response ) ) { $userinfo_body = wp_remote_retrieve_body( $userinfo_response ); $userinfo_data = json_decode( (string) $userinfo_body, true ); if ( is_array( $userinfo_data ) && ! empty( $userinfo_data['email'] ) ) { $connected_email = sanitize_email( (string) $userinfo_data['email'] ); } } } $options = get_option( $this->plugin->get_option_key(), [] ); if ( ! is_array( $options ) ) { $options = []; } $options['google_oauth_refresh_token'] = $refresh_token; $options['google_oauth_connected_email'] = $connected_email; $options['google_oauth_connected_at'] = time(); update_option( $this->plugin->get_option_key(), $options ); $url = add_query_arg( [ 'groq_ai_google_oauth' => 'success', 'groq_ai_google_oauth_message' => __( 'Google succesvol verbonden.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), ], $this->get_settings_page_url() ); wp_safe_redirect( $url ); exit; } public function handle_google_oauth_disconnect() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Geen toestemming.', GROQ_AI_PRODUCT_TEXT_DOMAIN ) ); } check_admin_referer( 'groq_ai_google_oauth_disconnect' ); $options = get_option( $this->plugin->get_option_key(), [] ); if ( ! is_array( $options ) ) { $options = []; } $options['google_oauth_refresh_token'] = ''; $options['google_oauth_connected_email'] = ''; $options['google_oauth_connected_at'] = 0; update_option( $this->plugin->get_option_key(), $options ); $url = add_query_arg( [ 'groq_ai_google_oauth' => 'success', 'groq_ai_google_oauth_message' => __( 'Google koppeling verwijderd.', GROQ_AI_PRODUCT_TEXT_DOMAIN ), ], $this->get_settings_page_url() ); wp_safe_redirect( $url ); exit; } public function render_modules_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } ?>
get_label() ) ); ?>
plugin->get_settings(); $defaults = $this->plugin->get_default_modules_settings(); $modules = isset( $settings['modules'] ) ? $settings['modules'] : $defaults; $config = isset( $modules['rankmath'] ) ? $modules['rankmath'] : ( $defaults['rankmath'] ?? [] ); $rankmath_active = $this->plugin->is_rankmath_active(); $enabled = $rankmath_active && ! empty( $config['enabled'] ); $keyword_limit = isset( $config['focus_keyword_limit'] ) ? absint( $config['focus_keyword_limit'] ) : ( $defaults['rankmath']['focus_keyword_limit'] ?? 3 ); $keyword_limit = $keyword_limit > 0 ? $keyword_limit : 3; $title_pixels = isset( $config['meta_title_pixel_limit'] ) ? absint( $config['meta_title_pixel_limit'] ) : ( $defaults['rankmath']['meta_title_pixel_limit'] ?? 580 ); $title_pixels = $title_pixels > 0 ? $title_pixels : 580; $pixel_limit = isset( $config['meta_description_pixel_limit'] ) ? absint( $config['meta_description_pixel_limit'] ) : ( $defaults['rankmath']['meta_description_pixel_limit'] ?? 920 ); $pixel_limit = $pixel_limit > 0 ? $pixel_limit : 920; $rankmath_active = $this->plugin->is_rankmath_active(); ?>
/>
/>
/>