feat: Update version to 1.7.0 and add term description length settings for AI-generated content
This commit is contained in:
@@ -635,11 +635,12 @@ class Groq_AI_Product_Text_Settings_Page {
|
||||
<th><?php esc_html_e( 'Slug', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?></th>
|
||||
<th><?php esc_html_e( 'Producten', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?></th>
|
||||
<th><?php esc_html_e( 'Woorden (omschrijving)', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?></th>
|
||||
<th><?php esc_html_e( 'Acties', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if ( empty( $rows ) ) : ?>
|
||||
<tr><td colspan="4"><?php esc_html_e( 'Geen categorieën gevonden.', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?></td></tr>
|
||||
<tr><td colspan="5"><?php esc_html_e( 'Geen categorieën gevonden.', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?></td></tr>
|
||||
<?php else : ?>
|
||||
<?php foreach ( $rows as $row ) : ?>
|
||||
<?php
|
||||
@@ -658,6 +659,11 @@ class Groq_AI_Product_Text_Settings_Page {
|
||||
<td><?php echo esc_html( isset( $row['slug'] ) ? $row['slug'] : '' ); ?></td>
|
||||
<td><?php echo esc_html( (string) $count ); ?></td>
|
||||
<td class="groq-ai-word-cell"><span class="groq-ai-word-count"><?php echo esc_html( (string) $words ); ?></span></td>
|
||||
<td class="groq-ai-term-actions">
|
||||
<button type="button" class="button button-secondary groq-ai-regenerate-term" data-term-id="<?php echo esc_attr( isset( $row['id'] ) ? (string) $row['id'] : '' ); ?>">
|
||||
<?php esc_html_e( 'Genereer opnieuw', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
@@ -903,6 +909,8 @@ class Groq_AI_Product_Text_Settings_Page {
|
||||
$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 );
|
||||
$term_top_limit = $this->plugin->get_term_top_description_char_limit( $settings );
|
||||
$term_bottom_limit = $this->plugin->get_term_bottom_description_char_limit( $settings );
|
||||
|
||||
?>
|
||||
<div class="wrap">
|
||||
@@ -954,6 +962,22 @@ class Groq_AI_Product_Text_Settings_Page {
|
||||
<th scope="row"><?php esc_html_e( 'Productattributen', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?></th>
|
||||
<td><?php $this->render_product_attribute_includes_field(); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Term omschrijving lengte (tekens)', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?></th>
|
||||
<td>
|
||||
<label style="display:block; margin-bottom:8px;">
|
||||
<span><?php esc_html_e( 'Korte omschrijving (top_description)', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?></span><br />
|
||||
<input type="number" name="<?php echo esc_attr( $option_key ); ?>[term_top_description_char_limit]" value="<?php echo esc_attr( $term_top_limit ); ?>" min="100" max="5000" step="10" />
|
||||
</label>
|
||||
<label style="display:block;">
|
||||
<span><?php esc_html_e( 'Lange omschrijving (bottom_description)', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?></span><br />
|
||||
<input type="number" name="<?php echo esc_attr( $option_key ); ?>[term_bottom_description_char_limit]" value="<?php echo esc_attr( $term_bottom_limit ); ?>" min="100" max="5000" step="10" />
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Deze waardes worden doorgegeven aan de AI met een marge van ±10%. Gebruik dit om bijvoorbeeld short-form (bv. 600 tekens) en long-form (bv. 1200 tekens) teksten te sturen.', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="groq-ai-image-mode"><?php esc_html_e( 'Afbeeldingen als context', GROQ_AI_PRODUCT_TEXT_DOMAIN ); ?></label></th>
|
||||
<td>
|
||||
@@ -1463,6 +1487,7 @@ class Groq_AI_Product_Text_Settings_Page {
|
||||
|
||||
if ( 0 === strpos( (string) $hook, 'settings_page_groq-ai-product-text-categories' ) ) {
|
||||
$bulk_taxonomy = 'product_cat';
|
||||
$bulk_allow_regen = true;
|
||||
$bulk_strings = [
|
||||
'statusIdle' => __( 'Bulk gestart. AI werkt de geselecteerde categorieën bij…', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
'statusProgress' => __( 'Categorie %1$s van %2$s: %3$s', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
@@ -1472,6 +1497,11 @@ class Groq_AI_Product_Text_Settings_Page {
|
||||
'logSuccess' => __( '%1$s gevuld (%2$d woorden).', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
'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 ),
|
||||
'confirmRegenerate' => __( 'Wil je categorie %s opnieuw laten schrijven?', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
'regenerateProgress' => __( '%s wordt opnieuw geschreven…', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
'regenerateDone' => __( '%s is bijgewerkt.', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
'regenerateError' => __( 'Kon %1$s niet bijwerken: %2$s', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
'regenerateBlocked' => __( 'Wacht tot de bulk generatie klaar is voordat je een categorie opnieuw genereert.', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
];
|
||||
} elseif ( 0 === strpos( (string) $hook, 'settings_page_groq-ai-product-text-brands' ) ) {
|
||||
$detected_taxonomy = $this->detect_brand_taxonomy();
|
||||
|
||||
@@ -537,16 +537,38 @@ class Groq_AI_Prompt_Builder {
|
||||
$keyword_limit = $this->settings_manager->get_rankmath_focus_keyword_limit( $settings );
|
||||
$title_pixels = $this->settings_manager->get_rankmath_meta_title_pixel_limit( $settings );
|
||||
$desc_pixels = $this->settings_manager->get_rankmath_meta_description_pixel_limit( $settings );
|
||||
$top_char_range = $this->get_char_limit_range_values( $this->settings_manager->get_term_top_description_char_limit( $settings ) );
|
||||
$bottom_char_range = $this->get_char_limit_range_values( $this->settings_manager->get_term_bottom_description_char_limit( $settings ) );
|
||||
|
||||
$top_description_text = __( 'Korte HTML-omschrijving (1 alinea) voor de standaard WordPress term description. Exact één alinea in <p>-tags.', GROQ_AI_PRODUCT_TEXT_DOMAIN );
|
||||
if ( $top_char_range ) {
|
||||
$top_description_text .= ' ' . sprintf(
|
||||
__( 'Doel: ~%1$d tekens (±10%% ⇒ %2$d–%3$d).', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
$top_char_range['limit'],
|
||||
$top_char_range['min'],
|
||||
$top_char_range['max']
|
||||
);
|
||||
}
|
||||
|
||||
$bottom_description_text = __( 'Uitgebreide HTML-omschrijving (helemaal onderaan), 2–4 alinea’s, met paragrafen en eventueel lijstjes.', GROQ_AI_PRODUCT_TEXT_DOMAIN );
|
||||
if ( $bottom_char_range ) {
|
||||
$bottom_description_text .= ' ' . sprintf(
|
||||
__( 'Doel: ~%1$d tekens (±10%% ⇒ %2$d–%3$d).', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
$bottom_char_range['limit'],
|
||||
$bottom_char_range['min'],
|
||||
$bottom_char_range['max']
|
||||
);
|
||||
}
|
||||
|
||||
$properties = [
|
||||
'top_description' => [
|
||||
'type' => 'string',
|
||||
'description' => __( 'Korte HTML-omschrijving (1 alinea) voor de standaard WordPress term description. Exact één alinea in <p>-tags.', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
'description' => $top_description_text,
|
||||
'minLength' => 20,
|
||||
],
|
||||
'bottom_description' => [
|
||||
'type' => 'string',
|
||||
'description' => __( 'Uitgebreide HTML-omschrijving (helemaal onderaan), 2–4 alinea’s, met paragrafen en eventueel lijstjes.', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
'description' => $bottom_description_text,
|
||||
'minLength' => 20,
|
||||
],
|
||||
];
|
||||
@@ -675,6 +697,8 @@ class Groq_AI_Prompt_Builder {
|
||||
'"top_description":"..."',
|
||||
'"bottom_description":"..."',
|
||||
];
|
||||
$top_char_range = $this->get_char_limit_range_values( $this->settings_manager->get_term_top_description_char_limit( $settings ) );
|
||||
$bottom_char_range = $this->get_char_limit_range_values( $this->settings_manager->get_term_bottom_description_char_limit( $settings ) );
|
||||
|
||||
$rankmath_enabled = $this->settings_manager->is_module_enabled( 'rankmath', $settings );
|
||||
if ( $rankmath_enabled ) {
|
||||
@@ -693,9 +717,42 @@ class Groq_AI_Prompt_Builder {
|
||||
$instruction .= ' ' . __( 'Zorg dat top_description en bottom_description geldige HTML bevatten. top_description moet exact één alinea zijn in <p>-tags. bottom_description moet 2–4 alinea’s bevatten.', GROQ_AI_PRODUCT_TEXT_DOMAIN );
|
||||
$instruction .= ' ' . __( 'Voeg geen extra tekst buiten het JSON-object toe.', GROQ_AI_PRODUCT_TEXT_DOMAIN );
|
||||
$instruction .= ' ' . __( 'Als in de context een sectie "Interne links" staat, verwerk dan 2–5 van deze links natuurlijk in bottom_description als HTML-links (<a href="URL">Anker</a>).', GROQ_AI_PRODUCT_TEXT_DOMAIN );
|
||||
if ( $top_char_range ) {
|
||||
$instruction .= ' ' . sprintf(
|
||||
__( 'Houd top_description rond %1$d tekens en blijf tussen %2$d en %3$d tekens (±10%% marge).', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
$top_char_range['limit'],
|
||||
$top_char_range['min'],
|
||||
$top_char_range['max']
|
||||
);
|
||||
}
|
||||
if ( $bottom_char_range ) {
|
||||
$instruction .= ' ' . sprintf(
|
||||
__( 'Houd bottom_description rond %1$d tekens en blijf tussen %2$d en %3$d tekens (±10%% marge).', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
|
||||
$bottom_char_range['limit'],
|
||||
$bottom_char_range['min'],
|
||||
$bottom_char_range['max']
|
||||
);
|
||||
}
|
||||
return $instruction;
|
||||
}
|
||||
|
||||
private function get_char_limit_range_values( $limit ) {
|
||||
$limit = absint( $limit );
|
||||
|
||||
if ( $limit <= 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$min = (int) floor( $limit * 0.9 );
|
||||
$max = (int) ceil( $limit * 1.1 );
|
||||
|
||||
return [
|
||||
'limit' => $limit,
|
||||
'min' => max( 1, $min ),
|
||||
'max' => max( $min, $max ),
|
||||
];
|
||||
}
|
||||
|
||||
private function resolve_term_bottom_description_meta_key( $term = null, $settings = null ) {
|
||||
$default_key = '';
|
||||
if ( is_array( $settings ) && isset( $settings['term_bottom_description_meta_key'] ) ) {
|
||||
@@ -716,9 +773,15 @@ class Groq_AI_Prompt_Builder {
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => $limit,
|
||||
'no_found_rows' => true,
|
||||
'meta_key' => 'total_sales',
|
||||
'orderby' => 'meta_value_num',
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'meta_query' => [
|
||||
[
|
||||
'key' => '_stock_status',
|
||||
'value' => 'instock',
|
||||
'compare' => '=',
|
||||
],
|
||||
],
|
||||
'tax_query' => [
|
||||
[
|
||||
'taxonomy' => $taxonomy,
|
||||
|
||||
@@ -52,6 +52,8 @@ class Groq_AI_Settings_Manager {
|
||||
'image_context_mode' => 'url',
|
||||
'image_context_limit' => 3,
|
||||
'response_format_compat' => false,
|
||||
'term_top_description_char_limit' => 600,
|
||||
'term_bottom_description_char_limit' => 1200,
|
||||
];
|
||||
|
||||
$settings = get_option( $this->option_key, [] );
|
||||
@@ -79,6 +81,15 @@ class Groq_AI_Settings_Manager {
|
||||
isset( $settings['product_attribute_includes'] ) ? $settings['product_attribute_includes'] : []
|
||||
);
|
||||
|
||||
$settings['term_top_description_char_limit'] = $this->sanitize_term_description_char_limit_value(
|
||||
isset( $settings['term_top_description_char_limit'] ) ? $settings['term_top_description_char_limit'] : $defaults['term_top_description_char_limit'],
|
||||
$defaults['term_top_description_char_limit']
|
||||
);
|
||||
$settings['term_bottom_description_char_limit'] = $this->sanitize_term_description_char_limit_value(
|
||||
isset( $settings['term_bottom_description_char_limit'] ) ? $settings['term_bottom_description_char_limit'] : $defaults['term_bottom_description_char_limit'],
|
||||
$defaults['term_bottom_description_char_limit']
|
||||
);
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
@@ -114,6 +125,8 @@ class Groq_AI_Settings_Manager {
|
||||
'image_context_mode' => 'url',
|
||||
'image_context_limit' => 3,
|
||||
'response_format_compat' => false,
|
||||
'term_top_description_char_limit' => 600,
|
||||
'term_bottom_description_char_limit' => 1200,
|
||||
];
|
||||
|
||||
$current_settings = $this->all();
|
||||
@@ -151,6 +164,15 @@ class Groq_AI_Settings_Manager {
|
||||
$context_fields['images'] = true;
|
||||
}
|
||||
|
||||
$top_char_limit = $this->sanitize_term_description_char_limit_value(
|
||||
isset( $raw_input['term_top_description_char_limit'] ) ? $raw_input['term_top_description_char_limit'] : $defaults['term_top_description_char_limit'],
|
||||
$defaults['term_top_description_char_limit']
|
||||
);
|
||||
$bottom_char_limit = $this->sanitize_term_description_char_limit_value(
|
||||
isset( $raw_input['term_bottom_description_char_limit'] ) ? $raw_input['term_bottom_description_char_limit'] : $defaults['term_bottom_description_char_limit'],
|
||||
$defaults['term_bottom_description_char_limit']
|
||||
);
|
||||
|
||||
return [
|
||||
'provider' => $provider,
|
||||
'model' => $model,
|
||||
@@ -174,6 +196,8 @@ class Groq_AI_Settings_Manager {
|
||||
'response_format_compat' => ! empty( $raw_input['response_format_compat'] ),
|
||||
'image_context_mode' => $image_mode,
|
||||
'image_context_limit' => $image_limit,
|
||||
'term_top_description_char_limit' => $top_char_limit,
|
||||
'term_bottom_description_char_limit' => $bottom_char_limit,
|
||||
'context_fields' => $context_fields,
|
||||
'modules' => $this->sanitize_modules_settings(
|
||||
$modules_posted ? $raw_input['modules'] : [],
|
||||
@@ -211,6 +235,22 @@ class Groq_AI_Settings_Manager {
|
||||
return $clean;
|
||||
}
|
||||
|
||||
private function sanitize_term_description_char_limit_value( $value, $default ) {
|
||||
$default_value = absint( $default ) > 0 ? absint( $default ) : 600;
|
||||
|
||||
if ( null === $value || '' === $value ) {
|
||||
$value = $default_value;
|
||||
}
|
||||
|
||||
$value = absint( $value );
|
||||
|
||||
if ( $value <= 0 ) {
|
||||
$value = $default_value;
|
||||
}
|
||||
|
||||
return max( 100, min( 5000, $value ) );
|
||||
}
|
||||
|
||||
public function get_context_field_definitions() {
|
||||
if ( null === $this->context_field_definitions ) {
|
||||
$this->context_field_definitions = [
|
||||
@@ -362,6 +402,26 @@ class Groq_AI_Settings_Manager {
|
||||
return $this->sanitize_image_context_limit_value( $limit );
|
||||
}
|
||||
|
||||
public function get_term_top_description_char_limit( $settings = null ) {
|
||||
if ( null === $settings ) {
|
||||
$settings = $this->all();
|
||||
}
|
||||
|
||||
$value = isset( $settings['term_top_description_char_limit'] ) ? $settings['term_top_description_char_limit'] : 600;
|
||||
|
||||
return $this->sanitize_term_description_char_limit_value( $value, 600 );
|
||||
}
|
||||
|
||||
public function get_term_bottom_description_char_limit( $settings = null ) {
|
||||
if ( null === $settings ) {
|
||||
$settings = $this->all();
|
||||
}
|
||||
|
||||
$value = isset( $settings['term_bottom_description_char_limit'] ) ? $settings['term_bottom_description_char_limit'] : 1200;
|
||||
|
||||
return $this->sanitize_term_description_char_limit_value( $value, 1200 );
|
||||
}
|
||||
|
||||
public function is_response_format_compat_enabled( $settings = null ) {
|
||||
if ( null === $settings ) {
|
||||
$settings = $this->all();
|
||||
|
||||
Reference in New Issue
Block a user