Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d19b36493 | |||
| 732c7ad393 | |||
| 0a605cf165 |
@@ -66,6 +66,14 @@ class SitiWebUpdater {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function get_latest_version_from_response() {
|
||||||
|
if ( empty( $this->github_response['tag_name'] ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ltrim( $this->github_response['tag_name'], 'vV' );
|
||||||
|
}
|
||||||
|
|
||||||
public function initialize() {
|
public function initialize() {
|
||||||
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'modify_transient' ), 10, 1 );
|
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'modify_transient' ), 10, 1 );
|
||||||
add_filter( 'plugins_api', array( $this, 'plugin_popup' ), 10, 3);
|
add_filter( 'plugins_api', array( $this, 'plugin_popup' ), 10, 3);
|
||||||
@@ -88,7 +96,13 @@ class SitiWebUpdater {
|
|||||||
|
|
||||||
$this->get_repository_info(); // Get the repo info
|
$this->get_repository_info(); // Get the repo info
|
||||||
|
|
||||||
$out_of_date = version_compare( $this->github_response['tag_name'], $checked[ $this->basename ], 'gt' ); // Check if we're out of date
|
$latest_version = $this->get_latest_version_from_response();
|
||||||
|
|
||||||
|
if ( null === $latest_version ) {
|
||||||
|
return $transient;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out_of_date = version_compare( $latest_version, $checked[ $this->basename ], 'gt' ); // Check if we're out of date
|
||||||
|
|
||||||
if( $out_of_date ) {
|
if( $out_of_date ) {
|
||||||
|
|
||||||
@@ -100,7 +114,7 @@ class SitiWebUpdater {
|
|||||||
'url' => $this->plugin["PluginURI"],
|
'url' => $this->plugin["PluginURI"],
|
||||||
'slug' => $slug,
|
'slug' => $slug,
|
||||||
'package' => $new_files,
|
'package' => $new_files,
|
||||||
'new_version' => $this->github_response['tag_name']
|
'new_version' => $latest_version
|
||||||
);
|
);
|
||||||
|
|
||||||
$transient->response[$this->basename] = (object) $plugin; // Return it in response
|
$transient->response[$this->basename] = (object) $plugin; // Return it in response
|
||||||
@@ -118,6 +132,11 @@ class SitiWebUpdater {
|
|||||||
if( $args->slug == current( explode( '/' , $this->basename ) ) ) { // And it's our slug
|
if( $args->slug == current( explode( '/' , $this->basename ) ) ) { // And it's our slug
|
||||||
|
|
||||||
$this->get_repository_info(); // Get our repo info
|
$this->get_repository_info(); // Get our repo info
|
||||||
|
$latest_version = $this->get_latest_version_from_response();
|
||||||
|
|
||||||
|
if ( null === $latest_version ) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
// Set it to an array
|
// Set it to an array
|
||||||
$plugin = array(
|
$plugin = array(
|
||||||
@@ -129,7 +148,7 @@ class SitiWebUpdater {
|
|||||||
'num_ratings' => '10823',
|
'num_ratings' => '10823',
|
||||||
'downloaded' => '14249',
|
'downloaded' => '14249',
|
||||||
'added' => '2016-01-05',
|
'added' => '2016-01-05',
|
||||||
'version' => $this->github_response['tag_name'],
|
'version' => $latest_version,
|
||||||
'author' => $this->plugin["AuthorName"],
|
'author' => $this->plugin["AuthorName"],
|
||||||
'author_profile' => $this->plugin["AuthorURI"],
|
'author_profile' => $this->plugin["AuthorURI"],
|
||||||
'last_updated' => $this->github_response['published_at'],
|
'last_updated' => $this->github_response['published_at'],
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
const modelSelect = document.getElementById('groq-ai-model-select');
|
const modelSelect = document.getElementById('groq-ai-model-select');
|
||||||
const refreshButton = document.getElementById('groq-ai-refresh-models');
|
const refreshButton = document.getElementById('groq-ai-refresh-models');
|
||||||
const refreshStatus = document.getElementById('groq-ai-refresh-models-status');
|
const refreshStatus = document.getElementById('groq-ai-refresh-models-status');
|
||||||
|
const excludedModels = data.excludedModels || {};
|
||||||
let currentModelValue = (modelSelect && modelSelect.dataset.currentModel) || data.currentModel || '';
|
let currentModelValue = (modelSelect && modelSelect.dataset.currentModel) || data.currentModel || '';
|
||||||
|
|
||||||
function toggleProviderRows() {
|
function toggleProviderRows() {
|
||||||
@@ -42,6 +43,32 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isModelAllowed(model, providerOverride) {
|
||||||
|
if (!model) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const provider = providerOverride || (providerSelect ? providerSelect.value : data.currentProvider);
|
||||||
|
if (!provider || !excludedModels[provider]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return excludedModels[provider].indexOf(model) === -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureCurrentModelAllowed(providerOverride) {
|
||||||
|
if (!currentModelValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isModelAllowed(currentModelValue, providerOverride)) {
|
||||||
|
currentModelValue = '';
|
||||||
|
if (modelSelect) {
|
||||||
|
modelSelect.dataset.currentModel = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function buildModelOptions() {
|
function buildModelOptions() {
|
||||||
if (!modelSelect || !data.providers) {
|
if (!modelSelect || !data.providers) {
|
||||||
return;
|
return;
|
||||||
@@ -53,6 +80,8 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensureCurrentModelAllowed(provider);
|
||||||
|
|
||||||
const models = Array.isArray(providerData.models) ? providerData.models : [];
|
const models = Array.isArray(providerData.models) ? providerData.models : [];
|
||||||
const frag = document.createDocumentFragment();
|
const frag = document.createDocumentFragment();
|
||||||
const placeholder = document.createElement('option');
|
const placeholder = document.createElement('option');
|
||||||
@@ -63,6 +92,9 @@
|
|||||||
|
|
||||||
let hasCurrent = false;
|
let hasCurrent = false;
|
||||||
models.forEach(function (model) {
|
models.forEach(function (model) {
|
||||||
|
if (!isModelAllowed(model, provider)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
option.value = model;
|
option.value = model;
|
||||||
option.textContent = model;
|
option.textContent = model;
|
||||||
@@ -72,7 +104,7 @@
|
|||||||
frag.appendChild(option);
|
frag.appendChild(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (currentModelValue && !hasCurrent) {
|
if (currentModelValue && !hasCurrent && isModelAllowed(currentModelValue, provider)) {
|
||||||
const extraOption = document.createElement('option');
|
const extraOption = document.createElement('option');
|
||||||
extraOption.value = currentModelValue;
|
extraOption.value = currentModelValue;
|
||||||
extraOption.textContent = currentModelValue;
|
extraOption.textContent = currentModelValue;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
/**
|
/**
|
||||||
* Plugin Name: SitiAI Product Teksten
|
* Plugin Name: SitiAI Product Teksten
|
||||||
* Description: Genereer productteksten met diverse AI-aanbieders rechtstreeks vanuit WooCommerce.
|
* Description: Genereer productteksten met diverse AI-aanbieders rechtstreeks vanuit WooCommerce.
|
||||||
* Version: 1.1.0
|
* Version: 1.2.1
|
||||||
* Author: SitiAI
|
* Author: SitiAI
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -29,27 +29,10 @@ if ( ! defined( 'GROQ_AI_PRODUCT_TEXT_VERSION' ) ) {
|
|||||||
|
|
||||||
if ( ! defined( 'GROQ_AI_DEBUG_TRACE_ADDED' ) && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
if ( ! defined( 'GROQ_AI_DEBUG_TRACE_ADDED' ) && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
||||||
define( 'GROQ_AI_DEBUG_TRACE_ADDED', true );
|
define( 'GROQ_AI_DEBUG_TRACE_ADDED', true );
|
||||||
|
|
||||||
set_error_handler(
|
|
||||||
function ( $errno, $errstr, $errfile, $errline ) {
|
|
||||||
$target_lines = [
|
|
||||||
'/wp-includes/functions.php:7291',
|
|
||||||
'/wp-includes/functions.php:2187',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ( $target_lines as $needle ) {
|
|
||||||
if ( false !== strpos( $errfile . ':' . $errline, $needle ) ) {
|
|
||||||
error_log( '[GroqAI Debug] ' . $errstr . ' | Stack: ' . wp_debug_backtrace_summary( null, 0, true ) );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once __DIR__ . '/includes/Core/class-groq-ai-service-container.php';
|
require_once __DIR__ . '/includes/Core/class-groq-ai-service-container.php';
|
||||||
|
require_once __DIR__ . '/includes/Core/class-groq-ai-model-exclusions.php';
|
||||||
require_once __DIR__ . '/includes/Core/class-groq-ai-ajax-controller.php';
|
require_once __DIR__ . '/includes/Core/class-groq-ai-ajax-controller.php';
|
||||||
require_once __DIR__ . '/includes/Contracts/interface-groq-ai-provider.php';
|
require_once __DIR__ . '/includes/Contracts/interface-groq-ai-provider.php';
|
||||||
require_once __DIR__ . '/includes/Providers/class-groq-ai-abstract-openai-provider.php';
|
require_once __DIR__ . '/includes/Providers/class-groq-ai-abstract-openai-provider.php';
|
||||||
@@ -78,6 +61,7 @@ $updater->initialize();
|
|||||||
final class Groq_AI_Product_Text_Plugin {
|
final class Groq_AI_Product_Text_Plugin {
|
||||||
const OPTION_KEY = 'groq_ai_product_text_settings';
|
const OPTION_KEY = 'groq_ai_product_text_settings';
|
||||||
const CONVERSATION_OPTION_KEY = 'groq_ai_product_text_conversations';
|
const CONVERSATION_OPTION_KEY = 'groq_ai_product_text_conversations';
|
||||||
|
const MODELS_CACHE_OPTION_KEY = 'groq_ai_product_text_models';
|
||||||
|
|
||||||
private static $instance = null;
|
private static $instance = null;
|
||||||
|
|
||||||
@@ -278,6 +262,10 @@ final class Groq_AI_Product_Text_Plugin {
|
|||||||
return $this->get_settings_manager()->is_response_format_compat_enabled( $settings );
|
return $this->get_settings_manager()->is_response_format_compat_enabled( $settings );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_image_context_mode( $settings = null ) {
|
||||||
|
return $this->get_settings_manager()->get_image_context_mode( $settings );
|
||||||
|
}
|
||||||
|
|
||||||
public function should_use_response_format( Groq_AI_Provider_Interface $provider, $settings ) {
|
public function should_use_response_format( Groq_AI_Provider_Interface $provider, $settings ) {
|
||||||
return ! $this->is_response_format_compat_enabled( $settings ) && $provider->supports_response_format();
|
return ! $this->is_response_format_compat_enabled( $settings ) && $provider->supports_response_format();
|
||||||
}
|
}
|
||||||
@@ -307,7 +295,78 @@ final class Groq_AI_Product_Text_Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function get_selected_model( Groq_AI_Provider_Interface $provider, $settings ) {
|
public function get_selected_model( Groq_AI_Provider_Interface $provider, $settings ) {
|
||||||
return ! empty( $settings['model'] ) ? $settings['model'] : $provider->get_default_model();
|
$provider_key = $provider->get_key();
|
||||||
|
$model = ! empty( $settings['model'] ) ? $settings['model'] : '';
|
||||||
|
$model = Groq_AI_Model_Exclusions::ensure_allowed( $provider_key, $model );
|
||||||
|
|
||||||
|
if ( '' === $model ) {
|
||||||
|
$default = Groq_AI_Model_Exclusions::ensure_allowed( $provider_key, $provider->get_default_model() );
|
||||||
|
if ( '' !== $default ) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
$available = Groq_AI_Model_Exclusions::filter_models( $provider_key, $provider->get_available_models() );
|
||||||
|
if ( ! empty( $available ) ) {
|
||||||
|
return $available[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_cached_models_for_provider( $provider ) {
|
||||||
|
$provider = sanitize_key( (string) $provider );
|
||||||
|
$cache = $this->get_models_cache();
|
||||||
|
|
||||||
|
return isset( $cache[ $provider ] ) ? $cache[ $provider ] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update_cached_models_for_provider( $provider, $models ) {
|
||||||
|
$provider = sanitize_key( (string) $provider );
|
||||||
|
$models = $this->sanitize_models_list( $models );
|
||||||
|
|
||||||
|
$cache = $this->get_models_cache();
|
||||||
|
$cache[ $provider ] = $models;
|
||||||
|
|
||||||
|
update_option( self::MODELS_CACHE_OPTION_KEY, $cache );
|
||||||
|
|
||||||
|
return $models;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function get_models_cache() {
|
||||||
|
$cache = get_option( self::MODELS_CACHE_OPTION_KEY, [] );
|
||||||
|
|
||||||
|
if ( ! is_array( $cache ) ) {
|
||||||
|
$cache = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ( $cache as $provider => $models ) {
|
||||||
|
$cache[ $provider ] = $this->sanitize_models_list( $models );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sanitize_models_list( $models ) {
|
||||||
|
if ( ! is_array( $models ) ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$models = array_map( 'sanitize_text_field', $models );
|
||||||
|
$models = array_filter(
|
||||||
|
$models,
|
||||||
|
function ( $model ) {
|
||||||
|
return '' !== $model;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$models = array_values( array_unique( $models ) );
|
||||||
|
|
||||||
|
if ( ! empty( $models ) ) {
|
||||||
|
sort( $models, SORT_NATURAL | SORT_FLAG_CASE );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $models;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function log_debug( $message, $context = [] ) {
|
public function log_debug( $message, $context = [] ) {
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ class Groq_AI_Logs_Table extends WP_List_Table {
|
|||||||
|
|
||||||
protected function column_created_at( $item ) {
|
protected function column_created_at( $item ) {
|
||||||
$date = esc_html( mysql2date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $item['created_at'] ) );
|
$date = esc_html( mysql2date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $item['created_at'] ) );
|
||||||
|
$usage = $this->get_usage_meta( $item );
|
||||||
$payload = [
|
$payload = [
|
||||||
'created_at' => $item['created_at'],
|
'created_at' => $item['created_at'],
|
||||||
'user' => $this->column_default( $item, 'user_id' ),
|
'user' => $this->column_default( $item, 'user_id' ),
|
||||||
@@ -149,6 +150,7 @@ class Groq_AI_Logs_Table extends WP_List_Table {
|
|||||||
'prompt' => $item['prompt'],
|
'prompt' => $item['prompt'],
|
||||||
'response' => $item['response'],
|
'response' => $item['response'],
|
||||||
'error_message' => $item['error_message'],
|
'error_message' => $item['error_message'],
|
||||||
|
'image_context' => isset( $usage['image_context'] ) ? $usage['image_context'] : null,
|
||||||
];
|
];
|
||||||
$encoded = esc_attr( wp_json_encode( $payload ) );
|
$encoded = esc_attr( wp_json_encode( $payload ) );
|
||||||
return sprintf(
|
return sprintf(
|
||||||
@@ -157,4 +159,14 @@ class Groq_AI_Logs_Table extends WP_List_Table {
|
|||||||
$date
|
$date
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function get_usage_meta( $item ) {
|
||||||
|
if ( empty( $item['usage_json'] ) ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = json_decode( $item['usage_json'], true );
|
||||||
|
|
||||||
|
return is_array( $data ) ? $data : [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,15 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
[ $this, 'render_logs_page' ]
|
[ $this, 'render_logs_page' ]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
add_submenu_page(
|
||||||
|
'options-general.php',
|
||||||
|
__( 'Siti AI Prompt instellingen', 'groq-ai-product-text' ),
|
||||||
|
__( 'Siti AI Prompt instellingen', 'groq-ai-product-text' ),
|
||||||
|
'manage_options',
|
||||||
|
'groq-ai-product-text-prompts',
|
||||||
|
[ $this, 'render_prompt_settings_page' ]
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hide_menu_links() {
|
public function hide_menu_links() {
|
||||||
@@ -50,7 +59,8 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
?>
|
?>
|
||||||
<style>
|
<style>
|
||||||
#adminmenu a[href="options-general.php?page=groq-ai-product-text-modules"],
|
#adminmenu a[href="options-general.php?page=groq-ai-product-text-modules"],
|
||||||
#adminmenu a[href="options-general.php?page=groq-ai-product-text-logs"] {
|
#adminmenu a[href="options-general.php?page=groq-ai-product-text-logs"],
|
||||||
|
#adminmenu a[href="options-general.php?page=groq-ai-product-text-prompts"] {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -96,36 +106,51 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add_settings_section(
|
||||||
|
'groq_ai_product_text_prompts',
|
||||||
|
__( 'Prompt instellingen', 'groq-ai-product-text' ),
|
||||||
|
'__return_false',
|
||||||
|
'groq-ai-product-text-prompts'
|
||||||
|
);
|
||||||
|
|
||||||
add_settings_field(
|
add_settings_field(
|
||||||
'groq_ai_store_context',
|
'groq_ai_store_context',
|
||||||
__( 'Winkelcontext', 'groq-ai-product-text' ),
|
__( 'Winkelcontext', 'groq-ai-product-text' ),
|
||||||
[ $this, 'render_store_context_field' ],
|
[ $this, 'render_store_context_field' ],
|
||||||
'groq-ai-product-text',
|
'groq-ai-product-text-prompts',
|
||||||
'groq_ai_product_text_general'
|
'groq_ai_product_text_prompts'
|
||||||
);
|
);
|
||||||
|
|
||||||
add_settings_field(
|
add_settings_field(
|
||||||
'groq_ai_default_prompt',
|
'groq_ai_default_prompt',
|
||||||
__( 'Standaard prompt', 'groq-ai-product-text' ),
|
__( 'Standaard prompt', 'groq-ai-product-text' ),
|
||||||
[ $this, 'render_default_prompt_field' ],
|
[ $this, 'render_default_prompt_field' ],
|
||||||
'groq-ai-product-text',
|
'groq-ai-product-text-prompts',
|
||||||
'groq_ai_product_text_general'
|
'groq_ai_product_text_prompts'
|
||||||
);
|
);
|
||||||
|
|
||||||
add_settings_field(
|
add_settings_field(
|
||||||
'groq_ai_context_fields',
|
'groq_ai_context_fields',
|
||||||
__( 'Standaard productcontext', 'groq-ai-product-text' ),
|
__( 'Standaard productcontext', 'groq-ai-product-text' ),
|
||||||
[ $this, 'render_context_fields_field' ],
|
[ $this, 'render_context_fields_field' ],
|
||||||
'groq-ai-product-text',
|
'groq-ai-product-text-prompts',
|
||||||
'groq_ai_product_text_general'
|
'groq_ai_product_text_prompts'
|
||||||
);
|
);
|
||||||
|
|
||||||
add_settings_field(
|
add_settings_field(
|
||||||
'groq_ai_response_format_compat',
|
'groq_ai_response_format_compat',
|
||||||
__( 'Response-format compatibiliteit', 'groq-ai-product-text' ),
|
__( 'Response-format compatibiliteit', 'groq-ai-product-text' ),
|
||||||
[ $this, 'render_response_format_compat_field' ],
|
[ $this, 'render_response_format_compat_field' ],
|
||||||
'groq-ai-product-text',
|
'groq-ai-product-text-prompts',
|
||||||
'groq_ai_product_text_general'
|
'groq_ai_product_text_prompts'
|
||||||
|
);
|
||||||
|
|
||||||
|
add_settings_field(
|
||||||
|
'groq_ai_image_context_mode',
|
||||||
|
__( 'Afbeeldingen toevoegen', 'groq-ai-product-text' ),
|
||||||
|
[ $this, 'render_image_context_mode_field' ],
|
||||||
|
'groq-ai-product-text-prompts',
|
||||||
|
'groq_ai_product_text_prompts'
|
||||||
);
|
);
|
||||||
|
|
||||||
add_settings_section(
|
add_settings_section(
|
||||||
@@ -144,6 +169,26 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function render_image_context_mode_field() {
|
||||||
|
$settings = $this->plugin->get_settings();
|
||||||
|
$mode = isset( $settings['image_context_mode'] ) ? $settings['image_context_mode'] : 'url';
|
||||||
|
$options = [
|
||||||
|
'none' => __( 'Nee, geen afbeeldingen', 'groq-ai-product-text' ),
|
||||||
|
'url' => __( 'Ja, voeg afbeeldings-URL’s toe aan de prompt', 'groq-ai-product-text' ),
|
||||||
|
'base64' => __( 'Ja, verstuur afbeeldingen als Base64 (indien ondersteund)', 'groq-ai-product-text' ),
|
||||||
|
];
|
||||||
|
?>
|
||||||
|
<select name="<?php echo esc_attr( $this->plugin->get_option_key() ); ?>[image_context_mode]">
|
||||||
|
<?php foreach ( $options as $value => $label ) : ?>
|
||||||
|
<option value="<?php echo esc_attr( $value ); ?>" <?php selected( $mode, $value ); ?>><?php echo esc_html( $label ); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<p class="description">
|
||||||
|
<?php esc_html_e( 'Bepaal hoe productafbeeldingen worden meegestuurd: helemaal niet, als URL’s in de prompt of als Base64-bijlagen voor modellen die beeldcontext ondersteunen.', 'groq-ai-product-text' ); ?>
|
||||||
|
</p>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
public function render_settings_page() {
|
public function render_settings_page() {
|
||||||
if ( ! current_user_can( 'manage_options' ) ) {
|
if ( ! current_user_can( 'manage_options' ) ) {
|
||||||
return;
|
return;
|
||||||
@@ -154,6 +199,9 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<h1><?php esc_html_e( 'Siti AI Productteksten', 'groq-ai-product-text' ); ?></h1>
|
<h1><?php esc_html_e( 'Siti AI Productteksten', 'groq-ai-product-text' ); ?></h1>
|
||||||
<p style="margin-bottom:16px;">
|
<p style="margin-bottom:16px;">
|
||||||
|
<a href="<?php echo esc_url( admin_url( 'admin.php?page=groq-ai-product-text-prompts' ) ); ?>" class="button button-primary">
|
||||||
|
<?php esc_html_e( 'Prompt instellingen', 'groq-ai-product-text' ); ?>
|
||||||
|
</a>
|
||||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=groq-ai-product-text-modules' ) ); ?>" class="button button-secondary">
|
<a href="<?php echo esc_url( admin_url( 'admin.php?page=groq-ai-product-text-modules' ) ); ?>" class="button button-secondary">
|
||||||
<?php esc_html_e( 'Ga naar modules', 'groq-ai-product-text' ); ?>
|
<?php esc_html_e( 'Ga naar modules', 'groq-ai-product-text' ); ?>
|
||||||
</a>
|
</a>
|
||||||
@@ -161,7 +209,7 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
<?php esc_html_e( 'Bekijk AI-logboek', 'groq-ai-product-text' ); ?>
|
<?php esc_html_e( 'Bekijk AI-logboek', 'groq-ai-product-text' ); ?>
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p><?php esc_html_e( 'Kies je AI-aanbieder, stel de juiste API-sleutel en het gewenste model in en beheer optionele winkelcontext of standaard prompt.', 'groq-ai-product-text' ); ?></p>
|
<p><?php esc_html_e( 'Kies je AI-aanbieder, stel de juiste API-sleutel en het gewenste model in.', 'groq-ai-product-text' ); ?></p>
|
||||||
<form action="options.php" method="post">
|
<form action="options.php" method="post">
|
||||||
<?php
|
<?php
|
||||||
settings_fields( 'groq_ai_product_text_group' );
|
settings_fields( 'groq_ai_product_text_group' );
|
||||||
@@ -169,11 +217,6 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
submit_button();
|
submit_button();
|
||||||
?>
|
?>
|
||||||
</form>
|
</form>
|
||||||
<div class="groq-ai-prompt-helper">
|
|
||||||
<h2><?php esc_html_e( 'Prompt generator', 'groq-ai-product-text' ); ?></h2>
|
|
||||||
<p><?php esc_html_e( 'Gebruik deze velden om belangrijke informatie voor de AI bij te houden (bijvoorbeeld tone of voice, USP’s of doelgroepen). Voeg ze toe aan je prompt met kopiëren en plakken.', 'groq-ai-product-text' ); ?></p>
|
|
||||||
<textarea class="large-text" rows="6" readonly><?php echo esc_textarea( $this->plugin->build_prompt_template_preview( $settings ) ); ?></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
@@ -198,6 +241,37 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function render_prompt_settings_page() {
|
||||||
|
if ( ! current_user_can( 'manage_options' ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$settings = $this->plugin->get_settings();
|
||||||
|
?>
|
||||||
|
<div class="wrap">
|
||||||
|
<h1><?php esc_html_e( 'Prompt instellingen', 'groq-ai-product-text' ); ?></h1>
|
||||||
|
<p style="margin-bottom:16px;">
|
||||||
|
<a href="<?php echo esc_url( admin_url( 'options-general.php?page=groq-ai-product-text' ) ); ?>" class="button button-secondary">
|
||||||
|
<?php esc_html_e( 'Terug naar algemene instellingen', 'groq-ai-product-text' ); ?>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p><?php esc_html_e( 'Beheer hier de winkelcontext, standaardprompt, productcontext en response-format instellingen. Deze keuzes bepalen hoe elke prompt richting de AI wordt opgebouwd.', 'groq-ai-product-text' ); ?></p>
|
||||||
|
<form action="options.php" method="post">
|
||||||
|
<?php
|
||||||
|
settings_fields( 'groq_ai_product_text_group' );
|
||||||
|
do_settings_sections( 'groq-ai-product-text-prompts' );
|
||||||
|
submit_button();
|
||||||
|
?>
|
||||||
|
</form>
|
||||||
|
<div class="groq-ai-prompt-helper">
|
||||||
|
<h2><?php esc_html_e( 'Prompt generator', 'groq-ai-product-text' ); ?></h2>
|
||||||
|
<p><?php esc_html_e( 'Gebruik deze velden om belangrijke informatie voor de AI bij te houden (bijvoorbeeld tone of voice, USP’s of doelgroepen). Voeg ze toe aan je prompt met kopiëren en plakken.', 'groq-ai-product-text' ); ?></p>
|
||||||
|
<textarea class="large-text" rows="6" readonly><?php echo esc_textarea( $this->plugin->build_prompt_template_preview( $settings ) ); ?></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
public function render_logs_page() {
|
public function render_logs_page() {
|
||||||
if ( ! current_user_can( 'manage_options' ) ) {
|
if ( ! current_user_can( 'manage_options' ) ) {
|
||||||
return;
|
return;
|
||||||
@@ -244,6 +318,20 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
<span id="groq-ai-log-tokens-total">—</span>
|
<span id="groq-ai-log-tokens-total">—</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="groq-ai-log-images">
|
||||||
|
<div>
|
||||||
|
<strong><?php esc_html_e( 'Afbeeldingsmodus', 'groq-ai-product-text' ); ?></strong>
|
||||||
|
<span id="groq-ai-log-images-mode">—</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong><?php esc_html_e( 'Beschikbare afbeeldingen', 'groq-ai-product-text' ); ?></strong>
|
||||||
|
<span id="groq-ai-log-images-available">—</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong><?php esc_html_e( 'Base64 meegestuurd', 'groq-ai-product-text' ); ?></strong>
|
||||||
|
<span id="groq-ai-log-images-base64">—</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -256,6 +344,7 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
.groq-ai-log-fields label{display:block;margin-bottom:15px;}
|
.groq-ai-log-fields label{display:block;margin-bottom:15px;}
|
||||||
.groq-ai-log-fields textarea{width:100%;}
|
.groq-ai-log-fields textarea{width:100%;}
|
||||||
.groq-ai-log-tokens{display:flex;gap:20px;margin-top:10px;}
|
.groq-ai-log-tokens{display:flex;gap:20px;margin-top:10px;}
|
||||||
|
.groq-ai-log-images{display:flex;gap:20px;margin-top:10px;}
|
||||||
.groq-ai-log-row{display:inline-block;}
|
.groq-ai-log-row{display:inline-block;}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
@@ -268,6 +357,9 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
const tokensPrompt=document.getElementById('groq-ai-log-tokens-prompt');
|
const tokensPrompt=document.getElementById('groq-ai-log-tokens-prompt');
|
||||||
const tokensCompletion=document.getElementById('groq-ai-log-tokens-completion');
|
const tokensCompletion=document.getElementById('groq-ai-log-tokens-completion');
|
||||||
const tokensTotal=document.getElementById('groq-ai-log-tokens-total');
|
const tokensTotal=document.getElementById('groq-ai-log-tokens-total');
|
||||||
|
const imagesMode=document.getElementById('groq-ai-log-images-mode');
|
||||||
|
const imagesAvailable=document.getElementById('groq-ai-log-images-available');
|
||||||
|
const imagesBase64=document.getElementById('groq-ai-log-images-base64');
|
||||||
const meta=document.querySelector('.groq-ai-log-meta');
|
const meta=document.querySelector('.groq-ai-log-meta');
|
||||||
function openModal(data){
|
function openModal(data){
|
||||||
if(!data){return;}
|
if(!data){return;}
|
||||||
@@ -276,6 +368,22 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
if(tokensPrompt){tokensPrompt.textContent=Number.isFinite(data.tokens_prompt)?data.tokens_prompt:'—';}
|
if(tokensPrompt){tokensPrompt.textContent=Number.isFinite(data.tokens_prompt)?data.tokens_prompt:'—';}
|
||||||
if(tokensCompletion){tokensCompletion.textContent=Number.isFinite(data.tokens_completion)?data.tokens_completion:'—';}
|
if(tokensCompletion){tokensCompletion.textContent=Number.isFinite(data.tokens_completion)?data.tokens_completion:'—';}
|
||||||
if(tokensTotal){tokensTotal.textContent=Number.isFinite(data.tokens_total)?data.tokens_total:'—';}
|
if(tokensTotal){tokensTotal.textContent=Number.isFinite(data.tokens_total)?data.tokens_total:'—';}
|
||||||
|
const imageContext=data.image_context||null;
|
||||||
|
if(imagesMode){
|
||||||
|
let mode='—';
|
||||||
|
if(imageContext){
|
||||||
|
mode=imageContext.effective_mode||imageContext.requested_mode||'—';
|
||||||
|
}
|
||||||
|
imagesMode.textContent=mode||'—';
|
||||||
|
}
|
||||||
|
if(imagesAvailable){
|
||||||
|
const available=imageContext&&Number.isFinite(imageContext.available)?imageContext.available:'—';
|
||||||
|
imagesAvailable.textContent=available;
|
||||||
|
}
|
||||||
|
if(imagesBase64){
|
||||||
|
const base64=imageContext&&Number.isFinite(imageContext.base64_sent)?imageContext.base64_sent:'—';
|
||||||
|
imagesBase64.textContent=base64;
|
||||||
|
}
|
||||||
if(meta){
|
if(meta){
|
||||||
meta.textContent=(data.provider||'')+' • '+(data.model||'')+' • '+(data.post_title||'')+' • '+(data.status||'');
|
meta.textContent=(data.provider||'')+' • '+(data.model||'')+' • '+(data.post_title||'')+' • '+(data.status||'');
|
||||||
}
|
}
|
||||||
@@ -515,7 +623,7 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function enqueue_settings_assets( $hook ) {
|
public function enqueue_settings_assets( $hook ) {
|
||||||
if ( ! in_array( $hook, [ 'settings_page_groq-ai-product-text', 'settings_page_groq-ai-product-text-modules' ], true ) ) {
|
if ( ! in_array( $hook, [ 'settings_page_groq-ai-product-text', 'settings_page_groq-ai-product-text-modules', 'settings_page_groq-ai-product-text-prompts' ], true ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -550,15 +658,19 @@ class Groq_AI_Product_Text_Settings_Page {
|
|||||||
'providerRows' => [],
|
'providerRows' => [],
|
||||||
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
|
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
|
||||||
'refreshNonce' => wp_create_nonce( 'groq_ai_refresh_models' ),
|
'refreshNonce' => wp_create_nonce( 'groq_ai_refresh_models' ),
|
||||||
|
'excludedModels' => Groq_AI_Model_Exclusions::get_all(),
|
||||||
'placeholders' => [
|
'placeholders' => [
|
||||||
'selectModel' => __( 'Selecteer een model via "Live modellen ophalen"', 'groq-ai-product-text' ),
|
'selectModel' => __( 'Selecteer een model via "Live modellen ophalen"', 'groq-ai-product-text' ),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ( $this->provider_manager->get_providers() as $provider ) {
|
foreach ( $this->provider_manager->get_providers() as $provider ) {
|
||||||
|
$provider_key = $provider->get_key();
|
||||||
|
$cached_models = $this->plugin->get_cached_models_for_provider( $provider_key );
|
||||||
|
$cached_models = Groq_AI_Model_Exclusions::filter_models( $provider_key, $cached_models );
|
||||||
$data['providers'][ $provider->get_key() ] = [
|
$data['providers'][ $provider->get_key() ] = [
|
||||||
'default_label' => sprintf( __( 'Gebruik standaardmodel (%s)', 'groq-ai-product-text' ), $provider->get_default_model() ),
|
'default_label' => sprintf( __( 'Gebruik standaardmodel (%s)', 'groq-ai-product-text' ), $provider->get_default_model() ),
|
||||||
'models' => [],
|
'models' => $cached_models,
|
||||||
'supports_live' => $provider->supports_live_models(),
|
'supports_live' => $provider->supports_live_models(),
|
||||||
];
|
];
|
||||||
$data['providerRows'][ $provider->get_key() ] = 'groq_ai_api_key_' . $provider->get_key();
|
$data['providerRows'][ $provider->get_key() ] = 'groq_ai_api_key_' . $provider->get_key();
|
||||||
|
|||||||
@@ -18,4 +18,6 @@ interface Groq_AI_Provider_Interface {
|
|||||||
public function fetch_live_models( $api_key );
|
public function fetch_live_models( $api_key );
|
||||||
|
|
||||||
public function supports_response_format();
|
public function supports_response_format();
|
||||||
|
|
||||||
|
public function supports_image_context();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,43 @@ class Groq_AI_Ajax_Controller {
|
|||||||
$system_prompt = $prompt_builder->build_system_prompt( $settings, $conversation_id );
|
$system_prompt = $prompt_builder->build_system_prompt( $settings, $conversation_id );
|
||||||
$model = $this->plugin->get_selected_model( $provider, $settings );
|
$model = $this->plugin->get_selected_model( $provider, $settings );
|
||||||
$context_fields = $prompt_builder->parse_context_fields_from_request( isset( $_POST['context_fields'] ) ? $_POST['context_fields'] : '', $settings );
|
$context_fields = $prompt_builder->parse_context_fields_from_request( isset( $_POST['context_fields'] ) ? $_POST['context_fields'] : '', $settings );
|
||||||
$product_context_text = $prompt_builder->build_product_context_block( $post_id, $context_fields );
|
$image_context_mode = $this->plugin->get_image_context_mode( $settings );
|
||||||
|
|
||||||
|
if ( 'none' === $image_context_mode ) {
|
||||||
|
$context_fields['images'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$image_context_enabled = ! empty( $context_fields['images'] );
|
||||||
|
$use_base64_payloads = $image_context_enabled && 'base64' === $image_context_mode && $provider->supports_image_context();
|
||||||
|
$image_context_count = $image_context_enabled ? $prompt_builder->get_product_image_count( $post_id ) : 0;
|
||||||
|
|
||||||
|
$prompt_image_mode = 'none';
|
||||||
|
if ( $image_context_enabled ) {
|
||||||
|
if ( $use_base64_payloads ) {
|
||||||
|
$prompt_image_mode = 'base64';
|
||||||
|
} else {
|
||||||
|
$prompt_image_mode = 'url';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( 'base64' === $image_context_mode && ! $provider->supports_image_context() ) {
|
||||||
|
$prompt_image_mode = 'url';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$product_context_text = $prompt_builder->build_product_context_block( $post_id, $context_fields, $prompt_image_mode );
|
||||||
|
$image_context_payloads = [];
|
||||||
|
if ( $use_base64_payloads ) {
|
||||||
|
$image_context_payloads = $prompt_builder->get_product_image_payloads( $post_id );
|
||||||
|
}
|
||||||
$prompt_with_context = $prompt_builder->prepend_context_to_prompt( $prompt, $product_context_text );
|
$prompt_with_context = $prompt_builder->prepend_context_to_prompt( $prompt, $product_context_text );
|
||||||
|
|
||||||
|
$image_context_meta = [
|
||||||
|
'requested_mode' => $image_context_mode,
|
||||||
|
'effective_mode' => $prompt_image_mode,
|
||||||
|
'available' => $image_context_count,
|
||||||
|
'base64_sent' => $use_base64_payloads ? count( $image_context_payloads ) : 0,
|
||||||
|
];
|
||||||
|
|
||||||
$response_format = null;
|
$response_format = null;
|
||||||
$use_response_format = $this->plugin->should_use_response_format( $provider, $settings );
|
$use_response_format = $this->plugin->should_use_response_format( $provider, $settings );
|
||||||
if ( $use_response_format ) {
|
if ( $use_response_format ) {
|
||||||
@@ -57,6 +91,7 @@ class Groq_AI_Ajax_Controller {
|
|||||||
'temperature' => 0.7,
|
'temperature' => 0.7,
|
||||||
'conversation_id' => $conversation_id,
|
'conversation_id' => $conversation_id,
|
||||||
'response_format' => $response_format,
|
'response_format' => $response_format,
|
||||||
|
'image_context' => $image_context_payloads,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -67,7 +102,9 @@ class Groq_AI_Ajax_Controller {
|
|||||||
'model' => $model,
|
'model' => $model,
|
||||||
'prompt' => $final_prompt,
|
'prompt' => $final_prompt,
|
||||||
'response' => '',
|
'response' => '',
|
||||||
'usage' => [],
|
'usage' => [
|
||||||
|
'image_context' => $image_context_meta,
|
||||||
|
],
|
||||||
'post_id' => $post_id,
|
'post_id' => $post_id,
|
||||||
'status' => 'error',
|
'status' => 'error',
|
||||||
'error_message' => $result->get_error_message(),
|
'error_message' => $result->get_error_message(),
|
||||||
@@ -78,6 +115,10 @@ class Groq_AI_Ajax_Controller {
|
|||||||
|
|
||||||
$response_text = $this->extract_content_text( $result );
|
$response_text = $this->extract_content_text( $result );
|
||||||
$response_usage = is_array( $result ) && isset( $result['usage'] ) ? $result['usage'] : [];
|
$response_usage = is_array( $result ) && isset( $result['usage'] ) ? $result['usage'] : [];
|
||||||
|
if ( ! is_array( $response_usage ) ) {
|
||||||
|
$response_usage = [];
|
||||||
|
}
|
||||||
|
$response_usage['image_context'] = $image_context_meta;
|
||||||
|
|
||||||
$response = $prompt_builder->parse_structured_response( $response_text, $settings );
|
$response = $prompt_builder->parse_structured_response( $response_text, $settings );
|
||||||
|
|
||||||
@@ -143,7 +184,10 @@ class Groq_AI_Ajax_Controller {
|
|||||||
wp_send_json_error( [ 'message' => $result->get_error_message() ], 500 );
|
wp_send_json_error( [ 'message' => $result->get_error_message() ], 500 );
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_send_json_success( [ 'models' => array_values( array_unique( $result ) ) ] );
|
$models = Groq_AI_Model_Exclusions::filter_models( $provider_key, array_values( array_unique( $result ) ) );
|
||||||
|
$models = $this->plugin->update_cached_models_for_provider( $provider_key, $models );
|
||||||
|
|
||||||
|
wp_send_json_success( [ 'models' => $models ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
private function extract_content_text( $result ) {
|
private function extract_content_text( $result ) {
|
||||||
|
|||||||
155
includes/Core/class-groq-ai-model-exclusions.php
Normal file
155
includes/Core/class-groq-ai-model-exclusions.php
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class Groq_AI_Model_Exclusions {
|
||||||
|
private const DEFAULT_EXCLUSIONS = [
|
||||||
|
'groq' => [
|
||||||
|
'playai-tts-arabic',
|
||||||
|
'moonshotai/kimi-k2-instruct',
|
||||||
|
'meta-llama/llama-prompt-guard-2-22m',
|
||||||
|
'groq/compound-mini',
|
||||||
|
'meta-llama/llama-guard-4-12b',
|
||||||
|
'openai/gpt-oss-20b',
|
||||||
|
'groq/compound',
|
||||||
|
'openai/gpt-oss-safeguard-20b',
|
||||||
|
'whisper-large-v3-turbo',
|
||||||
|
'meta-llama/llama-4-scout-17b-16e-instruct',
|
||||||
|
'allam-2-7b',
|
||||||
|
'playai-tts',
|
||||||
|
'moonshotai/kimi-k2-instruct-0905',
|
||||||
|
'whisper-large-v3',
|
||||||
|
'meta-llama/llama-prompt-guard-2-86m',
|
||||||
|
],
|
||||||
|
'openai' => [],
|
||||||
|
'google' => [
|
||||||
|
'embedding-gecko-001',
|
||||||
|
'embedding-001',
|
||||||
|
'text-embedding-004',
|
||||||
|
'gemini-embedding-exp-03-07',
|
||||||
|
'gemini-embedding-exp',
|
||||||
|
'gemini-embedding-001',
|
||||||
|
'gemini-2.5-flash-image-preview',
|
||||||
|
'gemini-2.5-flash-image',
|
||||||
|
'gemini-2.5-flash-preview-tts',
|
||||||
|
'gemini-2.5-pro-preview-tts',
|
||||||
|
'gemini-2.5-flash-native-audio-latest',
|
||||||
|
'gemini-2.5-flash-native-audio-preview-09-2025',
|
||||||
|
'gemini-2.5-computer-use-preview-10-2025',
|
||||||
|
'gemini-3-pro-image-preview',
|
||||||
|
'nano-banana-pro-preview',
|
||||||
|
'gemini-robotics-er-1.5-preview',
|
||||||
|
'deep-research-pro-preview-12-2025',
|
||||||
|
'aqa',
|
||||||
|
'imagen-4.0-generate-preview-06-06',
|
||||||
|
'imagen-4.0-ultra-generate-preview-06-06',
|
||||||
|
'imagen-4.0-generate-001',
|
||||||
|
'imagen-4.0-ultra-generate-001',
|
||||||
|
'imagen-4.0-fast-generate-001',
|
||||||
|
'veo-2.0-generate-001',
|
||||||
|
'veo-3.0-generate-001',
|
||||||
|
'veo-3.0-fast-generate-001',
|
||||||
|
'veo-3.1-generate-preview',
|
||||||
|
'veo-3.1-fast-generate-preview',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geeft de volledige lijst met uitgesloten modellen terug, gegroepeerd per aanbieder.
|
||||||
|
*
|
||||||
|
* @return array<string, string[]>
|
||||||
|
*/
|
||||||
|
public static function get_all() {
|
||||||
|
$list = apply_filters( 'groq_ai_model_exclusions', self::DEFAULT_EXCLUSIONS );
|
||||||
|
|
||||||
|
if ( ! is_array( $list ) ) {
|
||||||
|
$list = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$normalized = [];
|
||||||
|
foreach ( $list as $provider => $models ) {
|
||||||
|
$normalized[ self::normalize_provider( $provider ) ] = self::normalize_models_list( $models );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $provider
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public static function get_for_provider( $provider ) {
|
||||||
|
$provider = self::normalize_provider( $provider );
|
||||||
|
$list = self::get_all();
|
||||||
|
|
||||||
|
return isset( $list[ $provider ] ) ? $list[ $provider ] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function is_excluded( $provider, $model ) {
|
||||||
|
if ( '' === $model ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$model = sanitize_text_field( $model );
|
||||||
|
$provider = self::normalize_provider( $provider );
|
||||||
|
$list = self::get_for_provider( $provider );
|
||||||
|
|
||||||
|
return in_array( $model, $list, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $provider
|
||||||
|
* @param string $model
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function ensure_allowed( $provider, $model ) {
|
||||||
|
if ( self::is_excluded( $provider, $model ) ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $provider
|
||||||
|
* @param array $models
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function filter_models( $provider, $models ) {
|
||||||
|
if ( ! is_array( $models ) ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$provider = self::normalize_provider( $provider );
|
||||||
|
|
||||||
|
return array_values(
|
||||||
|
array_filter(
|
||||||
|
array_map(
|
||||||
|
'sanitize_text_field',
|
||||||
|
$models
|
||||||
|
),
|
||||||
|
function ( $model ) use ( $provider ) {
|
||||||
|
return ! self::is_excluded( $provider, $model );
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function normalize_provider( $provider ) {
|
||||||
|
return sanitize_key( (string) $provider );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function normalize_models_list( $models ) {
|
||||||
|
if ( ! is_array( $models ) ) {
|
||||||
|
$models = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$models = array_map( 'sanitize_text_field', $models );
|
||||||
|
$models = array_filter(
|
||||||
|
$models,
|
||||||
|
function ( $model ) {
|
||||||
|
return '' !== $model;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return array_values( array_unique( $models ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -138,4 +138,8 @@ abstract class Groq_AI_Abstract_OpenAI_Provider implements Groq_AI_Provider_Inte
|
|||||||
$field = $this->get_option_key();
|
$field = $this->get_option_key();
|
||||||
return isset( $settings[ $field ] ) ? $settings[ $field ] : '';
|
return isset( $settings[ $field ] ) ? $settings[ $field ] : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function supports_image_context() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ class Groq_AI_Provider_Google implements Groq_AI_Provider_Interface {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function supports_image_context() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public function fetch_live_models( $api_key ) {
|
public function fetch_live_models( $api_key ) {
|
||||||
$endpoint = add_query_arg(
|
$endpoint = add_query_arg(
|
||||||
[ 'key' => $api_key, 'pageSize' => 100 ],
|
[ 'key' => $api_key, 'pageSize' => 100 ],
|
||||||
@@ -92,15 +96,59 @@ class Groq_AI_Provider_Google implements Groq_AI_Provider_Interface {
|
|||||||
sprintf( 'https://generativelanguage.googleapis.com/v1beta/models/%s:generateContent', rawurlencode( $model ) )
|
sprintf( 'https://generativelanguage.googleapis.com/v1beta/models/%s:generateContent', rawurlencode( $model ) )
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$image_context = isset( $args['image_context'] ) && is_array( $args['image_context'] ) ? $args['image_context'] : [];
|
||||||
|
|
||||||
|
$parts = [];
|
||||||
|
|
||||||
|
if ( '' !== trim( (string) $system_prompt ) ) {
|
||||||
|
$parts[] = [
|
||||||
|
'text' => $system_prompt,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( '' !== trim( (string) $prompt ) ) {
|
||||||
|
$parts[] = [
|
||||||
|
'text' => $prompt,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $image_context ) ) {
|
||||||
|
foreach ( $image_context as $image ) {
|
||||||
|
if ( empty( $image['data'] ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$label = isset( $image['label'] ) ? trim( (string) $image['label'] ) : '';
|
||||||
|
if ( '' !== $label ) {
|
||||||
|
$parts[] = [
|
||||||
|
'text' => sprintf(
|
||||||
|
/* translators: %s: image label */
|
||||||
|
__( 'Contextafbeelding: %s', 'groq-ai-product-text' ),
|
||||||
|
$label
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts[] = [
|
||||||
|
'inline_data' => [
|
||||||
|
'mime_type' => ! empty( $image['mime_type'] ) ? $image['mime_type'] : 'image/jpeg',
|
||||||
|
'data' => $image['data'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty( $parts ) ) {
|
||||||
|
$parts[] = [
|
||||||
|
'text' => $prompt,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'contents' => [
|
'contents' => [
|
||||||
[
|
[
|
||||||
'role' => 'user',
|
'role' => 'user',
|
||||||
'parts' => [
|
'parts' => $parts,
|
||||||
[
|
|
||||||
'text' => $system_prompt . "\n\n" . $prompt,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'generationConfig' => [
|
'generationConfig' => [
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ class Groq_AI_Prompt_Builder {
|
|||||||
return $normalized;
|
return $normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function build_product_context_block( $post_id, $fields ) {
|
public function build_product_context_block( $post_id, $fields, $image_mode = 'url' ) {
|
||||||
$post_id = absint( $post_id );
|
$post_id = absint( $post_id );
|
||||||
|
|
||||||
if ( ! $post_id ) {
|
if ( ! $post_id ) {
|
||||||
@@ -162,6 +162,13 @@ class Groq_AI_Prompt_Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $fields['images'] ) && 'url' === $image_mode ) {
|
||||||
|
$images = $this->get_product_images_text( $post_id );
|
||||||
|
if ( $images ) {
|
||||||
|
$parts[] = sprintf( __( 'Afbeeldingen: %s', 'groq-ai-product-text' ), $images );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return implode( "\n\n", array_filter( $parts ) );
|
return implode( "\n\n", array_filter( $parts ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,4 +357,144 @@ class Groq_AI_Prompt_Builder {
|
|||||||
|
|
||||||
return implode( '; ', $lines );
|
return implode( '; ', $lines );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function get_product_images_text( $post_id ) {
|
||||||
|
$image_ids = $this->get_product_image_ids( $post_id );
|
||||||
|
|
||||||
|
if ( empty( $image_ids ) ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$entries = [];
|
||||||
|
|
||||||
|
foreach ( $image_ids as $index => $attachment_id ) {
|
||||||
|
$descriptor = $this->describe_product_image( $attachment_id, $index + 1 );
|
||||||
|
if ( ! $descriptor ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$entries[] = sprintf( '%s - %s', $descriptor['label'], $descriptor['url'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode( '; ', array_filter( $entries ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_product_image_payloads( $post_id, $limit = 3, $max_filesize = 1572864 ) {
|
||||||
|
$image_ids = array_slice( $this->get_product_image_ids( $post_id ), 0, max( 1, (int) $limit ) );
|
||||||
|
|
||||||
|
if ( empty( $image_ids ) ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$payloads = [];
|
||||||
|
|
||||||
|
foreach ( $image_ids as $index => $attachment_id ) {
|
||||||
|
$descriptor = $this->describe_product_image( $attachment_id, $index + 1 );
|
||||||
|
if ( ! $descriptor || empty( $descriptor['path'] ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $descriptor['path'];
|
||||||
|
|
||||||
|
if ( ! file_exists( $path ) || ! is_readable( $path ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filesize = filesize( $path );
|
||||||
|
if ( false !== $filesize && $filesize > $max_filesize ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = @file_get_contents( $path );
|
||||||
|
if ( false === $data ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$payloads[] = [
|
||||||
|
'attachment_id' => $attachment_id,
|
||||||
|
'label' => $descriptor['label'],
|
||||||
|
'mime_type' => $descriptor['mime_type'],
|
||||||
|
'data' => base64_encode( $data ),
|
||||||
|
'url' => $descriptor['url'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $payloads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_product_image_count( $post_id ) {
|
||||||
|
return count( $this->get_product_image_ids( $post_id ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private function get_product_image_ids( $post_id ) {
|
||||||
|
$post_id = absint( $post_id );
|
||||||
|
|
||||||
|
if ( ! $post_id ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$image_ids = [];
|
||||||
|
|
||||||
|
$featured_id = get_post_thumbnail_id( $post_id );
|
||||||
|
if ( $featured_id ) {
|
||||||
|
$image_ids[] = $featured_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gallery_ids = [];
|
||||||
|
if ( function_exists( 'wc_get_product' ) ) {
|
||||||
|
$product = wc_get_product( $post_id );
|
||||||
|
if ( $product ) {
|
||||||
|
$gallery_ids = (array) $product->get_gallery_image_ids();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty( $gallery_ids ) ) {
|
||||||
|
$raw_gallery = get_post_meta( $post_id, '_product_image_gallery', true );
|
||||||
|
if ( is_string( $raw_gallery ) && '' !== trim( $raw_gallery ) ) {
|
||||||
|
$gallery_ids = array_filter( array_map( 'absint', explode( ',', $raw_gallery ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $gallery_ids ) ) {
|
||||||
|
$image_ids = array_merge( $image_ids, $gallery_ids );
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_values( array_unique( array_filter( array_map( 'absint', $image_ids ) ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private function describe_product_image( $attachment_id, $position ) {
|
||||||
|
$url = wp_get_attachment_url( $attachment_id );
|
||||||
|
|
||||||
|
if ( ! $url ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$label = trim( (string) get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) );
|
||||||
|
if ( '' === $label ) {
|
||||||
|
$label = get_the_title( $attachment_id );
|
||||||
|
}
|
||||||
|
$label = trim( wp_strip_all_tags( (string) $label ) );
|
||||||
|
|
||||||
|
if ( '' === $label ) {
|
||||||
|
$label = sprintf( __( 'Afbeelding %d', 'groq-ai-product-text' ), $position );
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = get_attached_file( $attachment_id );
|
||||||
|
$mime = get_post_mime_type( $attachment_id );
|
||||||
|
if ( ! $mime && $path ) {
|
||||||
|
$mime = wp_get_image_mime( $path );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $mime && 0 !== strpos( $mime, 'image/' ) ) {
|
||||||
|
$mime = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'attachment_id' => $attachment_id,
|
||||||
|
'label' => $label,
|
||||||
|
'url' => esc_url_raw( $url ),
|
||||||
|
'path' => $path,
|
||||||
|
'mime_type' => $mime ? $mime : 'image/jpeg',
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class Groq_AI_Settings_Manager {
|
|||||||
'google_api_key' => '',
|
'google_api_key' => '',
|
||||||
'context_fields' => $this->get_default_context_fields(),
|
'context_fields' => $this->get_default_context_fields(),
|
||||||
'modules' => $this->get_default_modules_settings(),
|
'modules' => $this->get_default_modules_settings(),
|
||||||
|
'image_context_mode' => 'url',
|
||||||
'response_format_compat' => false,
|
'response_format_compat' => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -44,6 +45,19 @@ class Groq_AI_Settings_Manager {
|
|||||||
$settings = wp_parse_args( (array) $settings, $defaults );
|
$settings = wp_parse_args( (array) $settings, $defaults );
|
||||||
$settings['context_fields'] = $this->normalize_context_fields( isset( $settings['context_fields'] ) ? $settings['context_fields'] : [] );
|
$settings['context_fields'] = $this->normalize_context_fields( isset( $settings['context_fields'] ) ? $settings['context_fields'] : [] );
|
||||||
$settings['modules'] = $this->sanitize_modules_settings( isset( $settings['modules'] ) ? $settings['modules'] : [] );
|
$settings['modules'] = $this->sanitize_modules_settings( isset( $settings['modules'] ) ? $settings['modules'] : [] );
|
||||||
|
$settings['model'] = Groq_AI_Model_Exclusions::ensure_allowed( $settings['provider'], isset( $settings['model'] ) ? $settings['model'] : '' );
|
||||||
|
|
||||||
|
$image_mode = isset( $settings['image_context_mode'] ) ? sanitize_text_field( $settings['image_context_mode'] ) : 'url';
|
||||||
|
if ( 'none' === $image_mode ) {
|
||||||
|
$settings['context_fields']['images'] = false;
|
||||||
|
$settings['image_context_mode'] = 'none';
|
||||||
|
} elseif ( in_array( $image_mode, [ 'url', 'base64' ], true ) ) {
|
||||||
|
$settings['context_fields']['images'] = true;
|
||||||
|
$settings['image_context_mode'] = $image_mode;
|
||||||
|
} else {
|
||||||
|
$settings['context_fields']['images'] = true;
|
||||||
|
$settings['image_context_mode'] = 'url';
|
||||||
|
}
|
||||||
|
|
||||||
return $settings;
|
return $settings;
|
||||||
}
|
}
|
||||||
@@ -65,6 +79,7 @@ class Groq_AI_Settings_Manager {
|
|||||||
'google_api_key' => '',
|
'google_api_key' => '',
|
||||||
'context_fields' => $this->get_default_context_fields(),
|
'context_fields' => $this->get_default_context_fields(),
|
||||||
'modules' => $this->get_default_modules_settings(),
|
'modules' => $this->get_default_modules_settings(),
|
||||||
|
'image_context_mode' => 'url',
|
||||||
'response_format_compat' => false,
|
'response_format_compat' => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -80,16 +95,34 @@ class Groq_AI_Settings_Manager {
|
|||||||
$provider = 'groq';
|
$provider = 'groq';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$model = sanitize_text_field( $input['model'] );
|
||||||
|
$model = Groq_AI_Model_Exclusions::ensure_allowed( $provider, $model );
|
||||||
|
|
||||||
|
$image_mode = isset( $input['image_context_mode'] ) ? sanitize_text_field( $input['image_context_mode'] ) : $defaults['image_context_mode'];
|
||||||
|
$allowed_modes = [ 'none', 'base64', 'url' ];
|
||||||
|
if ( ! in_array( $image_mode, $allowed_modes, true ) ) {
|
||||||
|
$image_mode = 'url';
|
||||||
|
}
|
||||||
|
|
||||||
|
$context_fields = $this->normalize_context_fields( $context_posted ? $raw_input['context_fields'] : $defaults['context_fields'] );
|
||||||
|
|
||||||
|
if ( 'none' === $image_mode ) {
|
||||||
|
$context_fields['images'] = false;
|
||||||
|
} else {
|
||||||
|
$context_fields['images'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'provider' => $provider,
|
'provider' => $provider,
|
||||||
'model' => sanitize_text_field( $input['model'] ),
|
'model' => $model,
|
||||||
'store_context' => sanitize_textarea_field( $input['store_context'] ),
|
'store_context' => sanitize_textarea_field( $input['store_context'] ),
|
||||||
'default_prompt' => sanitize_textarea_field( $input['default_prompt'] ),
|
'default_prompt' => sanitize_textarea_field( $input['default_prompt'] ),
|
||||||
'groq_api_key' => sanitize_text_field( $input['groq_api_key'] ),
|
'groq_api_key' => sanitize_text_field( $input['groq_api_key'] ),
|
||||||
'openai_api_key' => sanitize_text_field( $input['openai_api_key'] ),
|
'openai_api_key' => sanitize_text_field( $input['openai_api_key'] ),
|
||||||
'google_api_key' => sanitize_text_field( $input['google_api_key'] ),
|
'google_api_key' => sanitize_text_field( $input['google_api_key'] ),
|
||||||
'response_format_compat' => ! empty( $raw_input['response_format_compat'] ),
|
'response_format_compat' => ! empty( $raw_input['response_format_compat'] ),
|
||||||
'context_fields' => $this->normalize_context_fields( $context_posted ? $raw_input['context_fields'] : $defaults['context_fields'] ),
|
'image_context_mode' => $image_mode,
|
||||||
|
'context_fields' => $context_fields,
|
||||||
'modules' => $this->sanitize_modules_settings(
|
'modules' => $this->sanitize_modules_settings(
|
||||||
$modules_posted ? $raw_input['modules'] : [],
|
$modules_posted ? $raw_input['modules'] : [],
|
||||||
$defaults['modules'],
|
$defaults['modules'],
|
||||||
@@ -122,6 +155,11 @@ class Groq_AI_Settings_Manager {
|
|||||||
'description' => __( 'Voeg gestructureerde productattributen toe (zoals kleur, maat, materiaal).', 'groq-ai-product-text' ),
|
'description' => __( 'Voeg gestructureerde productattributen toe (zoals kleur, maat, materiaal).', 'groq-ai-product-text' ),
|
||||||
'default' => false,
|
'default' => false,
|
||||||
],
|
],
|
||||||
|
'images' => [
|
||||||
|
'label' => __( 'Afbeeldingen', 'groq-ai-product-text' ),
|
||||||
|
'description' => __( 'Voeg een korte lijst toe met productafbeeldingen (beschrijving + URL).', 'groq-ai-product-text' ),
|
||||||
|
'default' => false,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,6 +257,17 @@ class Groq_AI_Settings_Manager {
|
|||||||
return max( 200, min( 2000, $value ) );
|
return max( 200, min( 2000, $value ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_image_context_mode( $settings = null ) {
|
||||||
|
if ( null === $settings ) {
|
||||||
|
$settings = $this->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
$mode = isset( $settings['image_context_mode'] ) ? sanitize_text_field( $settings['image_context_mode'] ) : 'url';
|
||||||
|
$allowed_modes = [ 'none', 'base64', 'url' ];
|
||||||
|
|
||||||
|
return in_array( $mode, $allowed_modes, true ) ? $mode : 'url';
|
||||||
|
}
|
||||||
|
|
||||||
public function is_response_format_compat_enabled( $settings = null ) {
|
public function is_response_format_compat_enabled( $settings = null ) {
|
||||||
if ( null === $settings ) {
|
if ( null === $settings ) {
|
||||||
$settings = $this->all();
|
$settings = $this->all();
|
||||||
|
|||||||
Reference in New Issue
Block a user