Plugin Directory

Changeset 3373984


Ignore:
Timestamp:
10/06/2025 09:43:12 PM (5 months ago)
Author:
alttextai
Message:

Update to version 1.10.14 - Fix ChatGPT prompt validation for UTF-8 characters and add real-time error feedback

Location:
alttext-ai/trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • alttext-ai/trunk/README.txt

    r3373949 r3373984  
    66Requires at least: 4.7
    77Tested up to: 6.8
    8 Stable tag: 1.10.13
     8Stable tag: 1.10.14
    99WC requires at least: 3.3
    1010WC tested up to: 10.1
     
    7070== Changelog ==
    7171
     72= 1.10.14 - 2025-10-06 =
     73* Fixed: ChatGPT prompts with special characters (β, →, ₂) now save correctly
     74* Improved: Real-time error messages when ChatGPT prompts are invalid
     75* Improved: Live character counter shows remaining space for ChatGPT prompts
     76
    7277= 1.10.13 - 2025-10-06 =
    7378* Fixed: Non-administrator users can now save settings when given permission to access the plugin
  • alttext-ai/trunk/admin/class-atai-settings.php

    r3373949 r3373984  
    558558   * @param string $input The text of the GPT prompt.
    559559   *
    560    * @return string Returns the prompt string if valid, otherwise an empty string.
     560   * @return string Returns the prompt string if valid, otherwise returns the old value with an error message.
    561561   */
    562562  public function sanitize_gpt_prompt( $input ) {
    563     if ( strlen($input) > 512 || strpos($input, "{{AltText}}") === false ) {
     563    // Use mb_strlen to count characters, not bytes, for UTF-8 consistency with HTML maxlength
     564    // Empty strings are allowed (user wants to clear the prompt)
     565    if ( empty( trim( $input ) ) ) {
    564566      return '';
    565567    }
    566     else {
    567       return sanitize_textarea_field($input);
    568     }
     568
     569    // Get old value to preserve it if validation fails
     570    $old_value = get_option( 'atai_gpt_prompt', '' );
     571
     572    // Check if prompt is too long (character count, not bytes)
     573    $char_count = mb_strlen( $input, 'UTF-8' );
     574    if ( $char_count > 512 ) {
     575      add_settings_error(
     576        'atai_gpt_prompt',
     577        'atai_gpt_prompt_too_long',
     578        sprintf(
     579          __( 'ChatGPT prompt is too long (%d characters). Maximum is 512 characters.', 'alttext-ai' ),
     580          $char_count
     581        ),
     582        'error'
     583      );
     584      return $old_value;
     585    }
     586
     587    // Check if prompt contains the required {{AltText}} macro
     588    if ( strpos( $input, '{{AltText}}' ) === false ) {
     589      add_settings_error(
     590        'atai_gpt_prompt',
     591        'atai_gpt_prompt_missing_macro',
     592        __( 'ChatGPT prompt must include the {{AltText}} macro, which will be replaced with the generated alt text.', 'alttext-ai' ),
     593        'error'
     594      );
     595      return $old_value;
     596    }
     597
     598    return sanitize_textarea_field( $input );
    569599  }
    570600
  • alttext-ai/trunk/admin/js/admin.js

    r3371885 r3373984  
    18821882    setTimeout(extendMediaTemplate, 500);
    18831883  });
     1884
     1885  /**
     1886   * Real-time ChatGPT prompt validation
     1887   */
     1888  document.addEventListener('DOMContentLoaded', () => {
     1889    const promptTextarea = document.getElementById('atai_gpt_prompt');
     1890    const errorsContainer = document.getElementById('atai_gpt_prompt_errors');
     1891    const missingMacroError = document.getElementById('atai_gpt_prompt_error_missing_macro');
     1892    const tooLongError = document.getElementById('atai_gpt_prompt_error_too_long');
     1893    const charCountSpan = document.getElementById('atai_gpt_prompt_char_count');
     1894    const charCounterSpan = document.getElementById('atai_gpt_prompt_char_counter');
     1895
     1896    if (!promptTextarea || !errorsContainer) {
     1897      return; // Not on settings page
     1898    }
     1899
     1900    function validatePrompt() {
     1901      const value = promptTextarea.value;
     1902      const charCount = value.length; // JavaScript .length counts UTF-16 code units, similar to mb_strlen
     1903      const hasMacro = value.includes('{{AltText}}');
     1904      const isTooLong = charCount > 512;
     1905      const isEmpty = value.trim() === '';
     1906
     1907      // Update character counter
     1908      if (charCounterSpan) {
     1909        charCounterSpan.textContent = `${charCount}/512`;
     1910
     1911        // Update counter color based on length
     1912        if (isTooLong) {
     1913          charCounterSpan.classList.remove('text-gray-400');
     1914          charCounterSpan.classList.add('text-red-500', 'font-medium');
     1915        } else if (charCount > 400) {
     1916          charCounterSpan.classList.remove('text-gray-400', 'text-red-500');
     1917          charCounterSpan.classList.add('text-amber-500', 'font-medium');
     1918        } else {
     1919          charCounterSpan.classList.remove('text-red-500', 'text-amber-500', 'font-medium');
     1920          charCounterSpan.classList.add('text-gray-400');
     1921        }
     1922      }
     1923
     1924      // Reset state
     1925      let hasErrors = false;
     1926      missingMacroError.classList.add('hidden');
     1927      tooLongError.classList.add('hidden');
     1928
     1929      // Check for missing macro (only if not empty)
     1930      if (!isEmpty && !hasMacro) {
     1931        missingMacroError.classList.remove('hidden');
     1932        hasErrors = true;
     1933      }
     1934
     1935      // Check for length
     1936      if (isTooLong) {
     1937        charCountSpan.textContent = charCount;
     1938        tooLongError.classList.remove('hidden');
     1939        hasErrors = true;
     1940      }
     1941
     1942      // Show/hide errors container
     1943      if (hasErrors) {
     1944        errorsContainer.classList.remove('hidden');
     1945      } else {
     1946        errorsContainer.classList.add('hidden');
     1947      }
     1948
     1949      // Update textarea appearance
     1950      if (hasErrors) {
     1951        promptTextarea.classList.remove('ring-gray-300', 'focus:ring-primary-600');
     1952        promptTextarea.classList.add('ring-red-300', 'focus:ring-red-600');
     1953      } else {
     1954        promptTextarea.classList.remove('ring-red-300', 'focus:ring-red-600');
     1955        promptTextarea.classList.add('ring-gray-300', 'focus:ring-primary-600');
     1956      }
     1957    }
     1958
     1959    // Validate on input (real-time)
     1960    promptTextarea.addEventListener('input', validatePrompt);
     1961
     1962    // Validate on paste
     1963    promptTextarea.addEventListener('paste', () => {
     1964      // Use setTimeout to validate after paste content is inserted
     1965      setTimeout(validatePrompt, 0);
     1966    });
     1967
     1968    // Initial validation on page load
     1969    validatePrompt();
     1970  });
    18841971})();
  • alttext-ai/trunk/admin/partials/settings.php

    r3373949 r3373984  
    503503                      placeholder="example: Rewrite the following text in the style of Shakespeare: {{AltText}}"
    504504                    ><?php echo esc_html ( get_option( 'atai_gpt_prompt' ) ); ?></textarea>
     505
     506                    <!-- Real-time validation error container -->
     507                    <div id="atai_gpt_prompt_errors" class="mt-2 hidden">
     508                      <div id="atai_gpt_prompt_error_missing_macro" class="p-3 bg-red-50 border border-red-200 rounded-md text-red-700 text-sm hidden">
     509                        <strong><?php esc_html_e( 'Missing required macro:', 'alttext-ai' ); ?></strong>
     510                        <?php esc_html_e( 'Your prompt must include {{AltText}} which will be replaced with the generated alt text.', 'alttext-ai' ); ?>
     511                      </div>
     512                      <div id="atai_gpt_prompt_error_too_long" class="p-3 bg-red-50 border border-red-200 rounded-md text-red-700 text-sm hidden">
     513                        <strong><?php esc_html_e( 'Prompt too long:', 'alttext-ai' ); ?></strong>
     514                        <span id="atai_gpt_prompt_char_count">0</span> <?php esc_html_e( 'characters. Maximum is 512 characters.', 'alttext-ai' ); ?>
     515                      </div>
     516                    </div>
    505517                  </div>
    506518                  <p class="mt-1 text-gray-500">
    507519                    <?php esc_html_e( 'Your prompt MUST include the macro {{AltText}}, which will be substituted with the generated alt text, then sent to ChatGPT.', 'alttext-ai' ); ?>
     520                    <span id="atai_gpt_prompt_char_counter" class="float-right text-xs text-gray-400">0/512</span>
    508521                  </p>
    509522                </div>
  • alttext-ai/trunk/atai.php

    r3373949 r3373984  
    1616 * Plugin URI:        https://alttext.ai/product
    1717 * Description:       Automatically generate image alt text with AltText.ai.
    18  * Version:           1.10.13
     18 * Version:           1.10.14
    1919 * Author:            AltText.ai
    2020 * Author URI:        https://alttext.ai
     
    3434 * Current plugin version.
    3535 */
    36 define( 'ATAI_VERSION', '1.10.13' );
     36define( 'ATAI_VERSION', '1.10.14' );
    3737
    3838/**
  • alttext-ai/trunk/changelog.txt

    r3373949 r3373984  
    11*** AltText.ai Changelog ***
     2
     32025-10-06 - version 1.10.14
     4* Fixed: ChatGPT prompts with special characters (β, →, ₂) now save correctly
     5* Improved: Real-time error messages when ChatGPT prompts are invalid
     6* Improved: Live character counter shows remaining space for ChatGPT prompts
    27
    382025-10-06 - version 1.10.13
Note: See TracChangeset for help on using the changeset viewer.