Add core classes and tests for Groq AI compatibility, logging, and model services

- Implement Groq_AI_Compatibility_Service to manage WooCommerce dependency and admin notices.
- Create Groq_AI_Log_Scheduler for scheduled log cleanup based on settings.
- Develop Groq_AI_Model_Service for model selection and caching.
- Add language translations in POT file for Dutch.
- Set up PHPUnit configuration and bootstrap for testing.
- Implement unit tests for model exclusions, provider request building, settings management, and term saving functionality.
This commit is contained in:
2026-01-31 17:48:46 +00:00
parent 26aabdb2d8
commit 6cff0b6f58
25 changed files with 3131 additions and 368 deletions

View File

@@ -435,9 +435,22 @@ class Groq_AI_Ajax_Controller {
check_ajax_referer( 'groq_ai_generate', 'nonce' );
$prompt = isset( $_POST['prompt'] ) ? sanitize_textarea_field( wp_unslash( $_POST['prompt'] ) ) : '';
$prompt = isset( $_POST['prompt'] ) ? sanitize_textarea_field( wp_unslash( $_POST['prompt'] ) ) : '';
$post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
if ( ! $post_id ) {
wp_send_json_error( [ 'message' => __( 'Post-ID ontbreekt.', GROQ_AI_PRODUCT_TEXT_DOMAIN ) ], 400 );
}
$post = get_post( $post_id );
if ( ! $post || is_wp_error( $post ) || 'product' !== $post->post_type ) {
wp_send_json_error( [ 'message' => __( 'Product niet gevonden.', GROQ_AI_PRODUCT_TEXT_DOMAIN ) ], 404 );
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
wp_send_json_error( [ 'message' => __( 'Je hebt geen toestemming om dit product te bewerken.', GROQ_AI_PRODUCT_TEXT_DOMAIN ) ], 403 );
}
$settings = $this->plugin->get_settings();
$provider_manager = $this->plugin->get_provider_manager();
$provider_key = $settings['provider'];

View File

@@ -0,0 +1,58 @@
<?php
class Groq_AI_Compatibility_Service {
/** @var bool */
private $missing_wc_notice = false;
public function maybe_deactivate_if_woocommerce_missing() {
if ( $this->is_woocommerce_active() ) {
return;
}
if ( ! function_exists( 'deactivate_plugins' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
deactivate_plugins( plugin_basename( GROQ_AI_PRODUCT_TEXT_FILE ) );
$this->missing_wc_notice = true;
add_action( 'admin_notices', [ $this, 'render_missing_wc_notice' ] );
}
public function render_missing_wc_notice() {
if ( ! $this->missing_wc_notice ) {
return;
}
?>
<div class="notice notice-error">
<p>
<?php esc_html_e( 'SitiAI Product Teksten vereist WooCommerce en is gedeactiveerd omdat WooCommerce niet actief is.', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?>
</p>
</div>
<?php
}
public function is_rankmath_active() {
if ( class_exists( 'RankMath' ) ) {
return true;
}
if ( ! function_exists( 'is_plugin_active' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
return function_exists( 'is_plugin_active' ) && is_plugin_active( 'seo-by-rank-math/rank-math.php' );
}
public function is_woocommerce_active() {
if ( class_exists( 'WooCommerce' ) ) {
return true;
}
if ( ! function_exists( 'is_plugin_active' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
return function_exists( 'is_plugin_active' ) && is_plugin_active( 'woocommerce/woocommerce.php' );
}
}

View File

@@ -0,0 +1,28 @@
<?php
class Groq_AI_Log_Scheduler {
/** @var Groq_AI_Settings_Manager */
private $settings_manager;
/** @var Groq_AI_Generation_Logger */
private $logger;
public function __construct( Groq_AI_Settings_Manager $settings_manager, Groq_AI_Generation_Logger $logger ) {
$this->settings_manager = $settings_manager;
$this->logger = $logger;
}
public function ensure_logs_cleanup_schedule() {
if ( wp_next_scheduled( 'groq_ai_cleanup_logs' ) ) {
return;
}
wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'groq_ai_cleanup_logs' );
}
public function cleanup_logs() {
$settings = $this->settings_manager->all();
$retention_days = $this->settings_manager->get_logs_retention_days( $settings );
$this->logger->cleanup_old_logs( $retention_days );
}
}

View File

@@ -0,0 +1,78 @@
<?php
class Groq_AI_Model_Service {
public function get_selected_model( Groq_AI_Provider_Interface $provider, $settings ) {
$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( Groq_AI_Product_Text_Plugin::MODELS_CACHE_OPTION_KEY, $cache );
return $models;
}
private function get_models_cache() {
$cache = get_option( Groq_AI_Product_Text_Plugin::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;
}
}