PluginProbe
Auto Alt Text / 2.5.0
Auto Alt Text v2.5.0
3.0.3 2.8.2 1.3.1 1.3.2 2.0.0 2.1.0 2.1.1 2.2.0 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.6.1 2.7.0 2.8.0 2.8.1 All 28 releases
auto-alt-text / src / App / Admin / PluginOptions.php

PluginOptions.php in Auto Alt Text 2.5.0, at src/App/Admin/PluginOptions.php

609 lines 32.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace AATXT\App\Admin;
4
5 use AATXT\App\Logging\DBLogger;
6 use AATXT\App\AIProviders\Azure\AzureTranslator;
7 use AATXT\App\Exceptions\Azure\AzureTranslateInstanceException;
8 use AATXT\App\Utilities\AssetsManager;
9 use AATXT\App\Utilities\Encryption;
10 use AATXT\Config\Constants;
11
12 class PluginOptions
13 {
14 private static ?self $instance = null;
15 private static AssetsManager $assetsManager;
16
17 private function __construct()
18 {
19 //
20 }
21
22 /**
23 * Manage the necessary hooks to implement plugin options and their pages
24 * @return void
25 */
26 public static function register(): void
27 {
28 if (is_null(self::$instance)) {
29 self::$instance = new self();
30 }
31
32 self::$assetsManager = AssetsManager::make();
33
34 add_action('admin_notices', [self::$instance, 'showEncryptionConstantsNotice']);
35
36 add_action('admin_enqueue_scripts', [self::$instance, 'enqueueAdminScripts'], 1);
37 add_action('admin_menu', [self::$instance, 'addOptionsPageToTheMenu']);
38 add_action('admin_init', [self::$instance, 'setupPluginOptions'], 10);
39 add_action('admin_init', [self::$instance, 'migrateEncryptionKeys'], 9);
40
41 // Encrypt API Keys on update
42 add_action('pre_update_option_' . Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_COMPUTER_VISION, [self::$instance, 'encryptDataOnUpdate'], 10, 3);
43 add_action('pre_update_option_' . Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_TRANSLATE_INSTANCE, [self::$instance, 'encryptDataOnUpdate'], 10, 3);
44 add_action('pre_update_option_' . Constants::AATXT_OPTION_FIELD_API_KEY_OPENAI, [self::$instance, 'encryptDataOnUpdate'], 10, 3);
45 add_action('pre_update_option_' . Constants::AATXT_OPTION_FIELD_API_KEY_ANTHROPIC, [self::$instance, 'encryptDataOnUpdate'], 10, 3);
46
47 add_action('admin_notices', [self::$instance, 'encryptionErrorNotice']);
48 }
49
50 /**
51 * Show an error notice if the encryption of the API Key fails
52 * @return void
53 */
54 public function encryptionErrorNotice(): void
55 {
56 $raw = get_option(Constants::AATXT_OPTION_FIELD_API_KEY_OPENAI);
57 $decrypted = Encryption::make()->decrypt((string) $raw);
58
59 if ($raw && $decrypted === '') {
60 $screen = get_current_screen();
61 $settingsScreenId = 'toplevel_page_' . Constants::AATXT_PLUGIN_OPTIONS_PAGE_SLUG;
62 $showLink = ! ( $screen && $screen->id === $settingsScreenId );
63
64 $settingsUrl = esc_url( menu_page_url(Constants::AATXT_PLUGIN_OPTIONS_PAGE_SLUG, false) );
65
66 echo '<div class="notice notice-error is-dismissible">';
67 echo '<p>';
68
69 echo '<strong>' . esc_html__('Auto Alt Text', 'auto-alt-text') . ':</strong> ';
70
71 echo esc_html__(
72 'There was a problem with the encryption of your API Key for alt text generation. Please re-enter the key and save.',
73 'auto-alt-text'
74 );
75
76 if ($showLink) {
77 echo ' <a href="' . $settingsUrl . '">'
78 . esc_html__('Go to settings page', 'auto-alt-text')
79 . '</a>.';
80 }
81 echo '</p>';
82 echo '</div>';
83 }
84 }
85
86 /**
87 * Print an admin notice containing the defines to be added
88 * to the wp-config.php.
89 */
90 public function showEncryptionConstantsNotice(): void
91 {
92 if ( ! is_admin() || ! current_user_can('manage_options') ) {
93 return;
94 }
95
96 $screen = function_exists('get_current_screen') ? get_current_screen() : null;
97 if ( ! $screen || $screen->id !== 'toplevel_page_' . Constants::AATXT_PLUGIN_OPTIONS_PAGE_SLUG ) {
98 return;
99 }
100
101 if ( defined('AATXT_ENCRYPTION_KEY') && defined('AATXT_ENCRYPTION_SALT') ) {
102 return;
103 }
104
105 $suggestedKey = bin2hex(random_bytes(32));
106 $suggestedSalt = bin2hex(random_bytes(32));
107 ?>
108 <div class="notice notice-info is-dismissible">
109 <p>
110 <?php
111 printf(
112 /* translators: “Optional” label */
113 __( '%s: you can add two lines to your wp-config.php to make your API key more resilient if WordPress salts ever change.', 'auto-alt-text' ),
114 '<strong>' . esc_html__( 'Optional', 'auto-alt-text' ) . '</strong>'
115 );
116 ?>
117 </p>
118 <pre style="background:#f5f5f5; padding:10px; border-radius:4px;">
119 define('AATXT_ENCRYPTION_KEY', '<?php echo esc_html( $suggestedKey ); ?>');
120 define('AATXT_ENCRYPTION_SALT', '<?php echo esc_html( $suggestedSalt ); ?>');
121 </pre>
122 <p>
123 <?php esc_html_e(
124 'Just paste them before the line “/* That\'s all, stop editing! Happy publishing. */” in wp-config.php.',
125 'auto-alt-text'
126 ); ?>
127 </p>
128 <p>
129 <?php esc_html_e(
130 "If you don't have the ability to edit the wp-config.php, don't worry because the plugin will still work without this change. If your site's salting keys change in the future, you will simply need to resave your API Key in the options below.",
131 "auto-alt-text"
132 ); ?>
133 </p>
134 </div>
135 <?php
136 }
137
138 public function migrateEncryptionKeys(): void
139 {
140 if ( ! defined('AATXT_ENCRYPTION_KEY') || ! defined('AATXT_ENCRYPTION_SALT') ) {
141 return;
142 }
143
144 update_option(Constants::AATXT_LEGACY_ENCRYPTION_MIGRATION_DONE, '0');
145
146 if ( get_option(Constants::AATXT_LEGACY_ENCRYPTION_MIGRATION_DONE) ) {
147 return;
148 }
149
150 Encryption::make()->migrateLegacyApiKeys();
151
152 update_option(Constants::AATXT_LEGACY_ENCRYPTION_MIGRATION_DONE, '1');
153 }
154
155 /**
156 * Encrypt data
157 * @param ?string $newValue
158 * @return ?string
159 */
160 public function encryptDataOnUpdate(?string $newValue): ?string
161 {
162 if (!empty($newValue)) {
163 $newValue = (Encryption::make())->encrypt($newValue);
164 }
165 return $newValue;
166 }
167
168 /**
169 * @return void
170 */
171 public static function enqueueAdminScripts(): void
172 {
173 $screen = get_current_screen();
174 $isMainOptionsPage = $screen->id === 'toplevel_page_' . Constants::AATXT_PLUGIN_OPTIONS_PAGE_SLUG;
175
176 if ($isMainOptionsPage || strpos($screen->id, Constants::AATXT_PLUGIN_SLUG . '_') !== false) {
177
178 $adminCss = self::$assetsManager->getAssetUrl('resources/js/admin.js', true);
179
180 wp_enqueue_style(Constants::AATXT_PLUGIN_ASSETS_HANDLE, $adminCss, [], false);
181
182 if ($isMainOptionsPage) {
183 $adminJs = self::$assetsManager->getAssetUrl('resources/js/admin.js', false);
184 wp_enqueue_script(Constants::AATXT_PLUGIN_ASSETS_HANDLE, $adminJs, [], false);
185 }
186
187 }
188 }
189
190 /**
191 * Create options pages
192 * @return void
193 */
194 public static function addOptionsPageToTheMenu(): void
195 {
196 add_menu_page('Auto Alt Text Options', 'Auto Alt Text', 'manage_options', Constants::AATXT_PLUGIN_OPTIONS_PAGE_SLUG, [self::$instance, 'optionsMainPage'], null, 99);
197 add_submenu_page(Constants::AATXT_PLUGIN_OPTIONS_PAGE_SLUG, 'Error Log', 'Error log', 'manage_options', Constants::AATXT_PLUGIN_OPTION_LOG_PAGE_SLUG, [self::$instance, 'logOptionsPage']);
198 }
199
200 /**
201 * Implement the page showing error log
202 * @return void
203 */
204 public static function logOptionsPage(): void
205 {
206 ?>
207 <div class="wrap">
208 <h1><?php esc_html_e('Auto Alt Text Error Log', 'auto-alt-text') ?></h1>
209 <div class="aat-options plugin-description">
210 <p>
211 <?php esc_html_e("If the alt text of your images was not generated correctly, you can find the reason in this log.", 'auto-alt-text'); ?>
212 <br>
213 <?php esc_html_e("Each line corresponds to an error generated by a call to the Azure or OpenAI API after uploading an image.", 'auto-alt-text'); ?>
214 </p>
215 <?php
216 $logs = DBLogger::make()->getImageLog();
217 if ($logs) {
218 echo '<textarea id="error-log" name="error-log" readonly>' . esc_textarea($logs) . '</textarea>';
219 } else {
220 echo '<p>' . esc_html__('There is no error log yet!', 'auto-alt-text') . '</p>';
221 }
222
223 ?>
224 </div>
225 </div>
226 <?php
227 }
228
229 /**
230 * Implement the main option page
231 * @return void
232 */
233 public static function optionsMainPage(): void
234 {
235 ?>
236 <div class="wrap">
237 <h1><?php esc_html_e('Auto Alt Text Options', 'auto-alt-text') ?></h1>
238
239 <div class="aat-options plugin-description">
240 <p>
241 <?php esc_html_e("This plugin allows you to automatically generate Alt Text for the images that are uploaded to the site's media library.", 'auto-alt-text'); ?>
242 <br>
243 <?php esc_html_e("The following methods are available to generate the alt text:", 'auto-alt-text'); ?>
244 </p>
245 <ul>
246 <li>
247 <strong><?php esc_html_e("OpenAI's APIs", 'auto-alt-text'); ?></strong>: <?php esc_html_e("the image will be analyzed by the AI services provided by OpenAI and an alt text will be generated based on the prompt you set;", 'auto-alt-text'); ?>
248 </li>
249 <li>
250 <strong><?php esc_html_e("Azure's APIs", 'auto-alt-text'); ?></strong>: <?php esc_html_e("the image will be analyzed by the AI services provided by Azure and an alt text will be generated in the language of your choice;", 'auto-alt-text'); ?>
251 </li>
252 <li>
253 <strong><?php esc_html_e("Title of the article (not AI)", 'auto-alt-text'); ?></strong>: <?php esc_html_e("if the image is uploaded within an article, the title of the article will be used as alt text;", 'auto-alt-text'); ?>
254 </li>
255 <li>
256 <strong><?php esc_html_e("Title of the attachment (not AI)", 'auto-alt-text'); ?></strong>: <?php esc_html_e("the title of the attachment will be copied into the alt text;", 'auto-alt-text'); ?>
257 </li>
258 </ul>
259 <p><?php esc_html_e("Once all the necessary data for the chosen generation method has been entered, the alt texts will be created automatically upon uploading each image.", 'auto-alt-text'); ?></p>
260 <p><strong>New</strong>: <?php esc_html_e("For images already in the media library, you can create bulk alt texts. Open the Media Library in the \"list\" view, select the images for which to generate the alt text, and choose the \"Generate alt text\" bulk action. (Depending on the number of images chosen and their weight, this may take some time.)", 'auto-alt-text'); ?></p>
261 <p>
262 <strong><?php esc_html_e('Pay attention please:', 'auto-alt-text') ?></strong> <?php esc_html_e("if the alt text for an image is not generated, check the logs on the", 'auto-alt-text'); ?>
263 <a href="<?php esc_url(menu_page_url(Constants::AATXT_PLUGIN_OPTION_LOG_PAGE_SLUG, true)); ?>"><?php esc_html_e('designated page.', 'auto-alt-text') ?></a>
264 </p>
265 </div>
266 <form method="post" action="options.php" class="aat-options">
267 <?php
268 settings_fields('auto_alt_text_options');
269
270 echo '<div>';
271 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_TYPOLOGY) . '">' . esc_html__('Generation method', 'auto-alt-text') . '</label>';
272 echo '<p class="description">' . esc_html__("Which method do you want to use to generate the alt text for the images?", 'auto-alt-text') . '</p>';
273 $typology = self::typology();
274
275 ?>
276
277 <select name="<?php echo esc_attr(Constants::AATXT_OPTION_FIELD_TYPOLOGY); ?>"
278 id="<?php echo esc_attr(Constants::AATXT_OPTION_FIELD_TYPOLOGY); ?>">
279 <option value="<?php echo esc_attr(Constants::AATXT_OPTION_TYPOLOGY_DEACTIVATED); ?>"<?php echo esc_attr(self::selected($typology, Constants::AATXT_OPTION_TYPOLOGY_DEACTIVATED)); ?>><?php esc_html_e("Deactivated", 'auto-alt-text'); ?></option>
280 <option value="<?php echo esc_attr(Constants::AATXT_OPTION_TYPOLOGY_CHOICE_OPENAI); ?>"<?php echo esc_attr(self::selected($typology, Constants::AATXT_OPTION_TYPOLOGY_CHOICE_OPENAI)); ?>><?php esc_html_e("OpenAI's APIs", 'auto-alt-text'); ?></option>
281 <option value="<?php echo esc_attr(Constants::AATXT_OPTION_TYPOLOGY_CHOICE_ANTHROPIC); ?>"<?php echo esc_attr(self::selected($typology, Constants::AATXT_OPTION_TYPOLOGY_CHOICE_ANTHROPIC)); ?>><?php esc_html_e("Antrhopic's APIs", 'auto-alt-text'); ?></option>
282 <option value="<?php echo esc_attr(Constants::AATXT_OPTION_TYPOLOGY_CHOICE_AZURE); ?>"<?php echo esc_attr(self::selected($typology, Constants::AATXT_OPTION_TYPOLOGY_CHOICE_AZURE)); ?>><?php esc_html_e("Azure's APIs", 'auto-alt-text'); ?></option>
283 <option value="<?php echo esc_attr(Constants::AATXT_OPTION_TYPOLOGY_CHOICE_ARTICLE_TITLE); ?>"<?php echo esc_attr(self::selected($typology, Constants::AATXT_OPTION_TYPOLOGY_CHOICE_ARTICLE_TITLE)); ?>><?php esc_html_e("Title of the article (not AI)", 'auto-alt-text'); ?></option>
284 <option value="<?php echo esc_attr(Constants::AATXT_OPTION_TYPOLOGY_CHOICE_ATTACHMENT_TITLE); ?>"<?php echo esc_attr(self::selected($typology, Constants::AATXT_OPTION_TYPOLOGY_CHOICE_ATTACHMENT_TITLE)); ?>><?php esc_html_e("Title of the attachment (not AI)", 'auto-alt-text'); ?></option>
285 </select>
286 <?php
287 echo '</div>';
288
289 echo '<div class="plugin-option type-article-title"><strong>' . esc_html__('Notice', 'auto-alt-text') . '</strong>: ' .
290 esc_html__('If you try to insert an image into a post that has not yet been saved as a draft or published, the plugin cannot generate an alt text based on the post\'s title since the title itself has not yet been saved.', 'auto-alt-text') . ' ' .
291 esc_html__('Therefore, the alt text "Auto draft" will be inserted. To avoid this behavior, save the article draft first and then upload the image.', 'auto-alt-text') .
292 '</div>';
293
294 $openaiModel = self::openAiModel();
295
296 echo '<div class="plugin-option type-openai">';
297 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_MODEL_OPENAI) . '">' . esc_html__('Model', 'auto-alt-text') . '</label>';
298
299 echo '<select name="' . esc_attr(Constants::AATXT_OPTION_FIELD_MODEL_OPENAI) . '" id="' . esc_attr(Constants::AATXT_OPTION_FIELD_MODEL_OPENAI) . '">';
300 foreach(Constants::AATXT_OPTION_FIELD_MODEL_OPENAI_OPTIONS as $key => $value) {
301 echo '<option value="' . esc_attr($key) . '" ' . esc_attr(self::selected($openaiModel, $key)) . '>' . esc_html($value) . '</option>';
302 }
303 echo '</select>';
304 echo '</div>';
305
306 echo '<div class="plugin-option type-openai"><strong>' . esc_html__('Notice', 'auto-alt-text') . '</strong>: ' .
307 esc_html__('Rarely it may happen that the chosen model fails to generate correct alt text for the image.', 'auto-alt-text') . ' ' .
308 esc_html__('In these cases, the call to the api will be re-performed using the gpt-4o-mini model as fallback.', 'auto-alt-text') . '<br>' .
309 esc_html__('In case of errors, it is still possible to find the specific reason stated on the', 'auto-alt-text') . ' <a href="' . esc_url(menu_page_url(Constants::AATXT_PLUGIN_OPTION_LOG_PAGE_SLUG, false)) . '">' . esc_html__('error log page', 'auto-alt-text') . '</a>.' .
310 '</div>';
311
312 echo '<div class="plugin-option type-openai">';
313 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_API_KEY_OPENAI) . '">' . esc_html__('OpenAI API Key', 'auto-alt-text') . '</label>';
314 echo '<p class="description">' . esc_html__("Enter your API Key", 'auto-alt-text') . '</p>';
315 $apiKey = get_option(Constants::AATXT_OPTION_FIELD_API_KEY_OPENAI);
316 echo '<input type="password" name="' . esc_attr(Constants::AATXT_OPTION_FIELD_API_KEY_OPENAI) . '" value="' . esc_attr((Encryption::make())->decrypt($apiKey)) . '" />';
317 echo '</div>';
318
319 echo '<div class="plugin-option type-openai">';
320 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_PROMPT_OPENAI) . '">' . esc_html__('Prompt', 'auto-alt-text') . '</label>';
321 echo '<p class="description">' . esc_html__("Enter a specific and detailed prompt according to your needs.", 'auto-alt-text') . '</p>';
322 $defaultPrompt = sprintf(esc_html__("Act like an SEO expert and write an alt text of up to 125 characters for this image.", 'auto-alt-text'), Constants::AATXT_IMAGE_URL_TAG);
323 $prompt = get_option(Constants::AATXT_OPTION_FIELD_PROMPT_OPENAI) ?: $defaultPrompt;
324 echo '<textarea name="' . esc_attr(Constants::AATXT_OPTION_FIELD_PROMPT_OPENAI) . '" rows="5" cols="50">' . esc_textarea($prompt) . '</textarea>';
325 echo '</div>';
326
327 echo '<div class="plugin-option type-azure">' . esc_html__("Fill out the following fields to leverage Azure's computer vision services to generate the Alt texts.", 'auto-alt-text') . '</div>';
328
329 echo '<div class="plugin-option type-azure">';
330 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_COMPUTER_VISION) . '">' . esc_html__('Azure Computer Vision API Key', 'auto-alt-text') . '</label>';
331 echo '<p class="description">' . esc_html__("Enter the API key for the Computer Vision service of your Azure account.", 'auto-alt-text') . '</p>';
332 $apiKey = get_option(Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_COMPUTER_VISION);
333 echo '<input type="password" name="' . esc_attr(Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_COMPUTER_VISION) . '" value="' . esc_attr((Encryption::make())->decrypt($apiKey)) . '" />';
334 echo '</div>';
335
336 echo '<div class="plugin-option type-azure">';
337 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_ENDPOINT_AZURE_COMPUTER_VISION) . '">' . esc_html__('Azure Computer Vision Endpoint', 'auto-alt-text') . '</label>';
338 echo '<p class="description">' . esc_html__("Enter the endpoint of the Computer Vision service.", 'auto-alt-text') . ' (es. https://computer-vision-france-central.cognitiveservices.azure.com/)</p>';
339 $endpoint = get_option(Constants::AATXT_OPTION_FIELD_ENDPOINT_AZURE_COMPUTER_VISION);
340 echo '<input type="text" name="' . esc_attr(Constants::AATXT_OPTION_FIELD_ENDPOINT_AZURE_COMPUTER_VISION) . '" value="' . esc_attr($endpoint) . '" />';
341 echo '</div>';
342
343 echo '<div class="plugin-option type-azure">' .
344 '<strong>' . esc_html__('The default alt text language is English.', 'auto-alt-text') . '</strong><br>' .
345 esc_html__('If you want to translate into another language, enter the following data necessary for the translation API to work.', 'auto-alt-text') . ' ' .
346 esc_html__('After saving the changes you can select the desired language.', 'auto-alt-text') .
347 '</div>';
348
349 echo '<div class="plugin-option type-azure">';
350 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_TRANSLATE_INSTANCE) . '">' . esc_html__('Azure Translate Instance API Key', 'auto-alt-text') . '</label>';
351 echo '<p class="description">' . esc_html__("Enter your API key for the Azure Translate Instance service.", 'auto-alt-text') . '</p>';
352 $translationApiKey = get_option(Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_TRANSLATE_INSTANCE);
353 echo '<input type="password" name="' . esc_attr(Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_TRANSLATE_INSTANCE) . '" value="' . esc_attr((Encryption::make())->decrypt($translationApiKey)) . '" class="notRequired" />';
354 echo '</div>';
355
356 echo '<div class="plugin-option type-azure">';
357 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_ENDPOINT_AZURE_TRANSLATE_INSTANCE) . '">' . esc_html__('Azure Translate Instance Endpoint', 'auto-alt-text') . '</label>';
358 echo '<p class="description">' . esc_html__("Enter the endpoint of the Translate Instance service", 'auto-alt-text') . ' (es. https://api.cognitive.microsofttranslator.com/)</p>';
359 $translationEndpoint = get_option(Constants::AATXT_OPTION_FIELD_ENDPOINT_AZURE_TRANSLATE_INSTANCE);
360 echo '<input type="text" name="' . esc_attr(Constants::AATXT_OPTION_FIELD_ENDPOINT_AZURE_TRANSLATE_INSTANCE) . '" value="' . esc_attr($translationEndpoint) . '" class="notRequired" />';
361 echo '</div>';
362
363 echo '<div class="plugin-option type-azure">';
364 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_REGION_AZURE_TRANSLATE_INSTANCE) . '">' . esc_html__('Azure Translate Instance Region', 'auto-alt-text') . '</label>';
365 echo '<p class="description">' . esc_html__("Enter the region of the Azure Translate Instance service.", 'auto-alt-text') . ' (es. westeurope)</p>';
366 $translationRegion = get_option(Constants::AATXT_OPTION_FIELD_REGION_AZURE_TRANSLATE_INSTANCE);
367 echo '<input type="text" name="' . esc_attr(Constants::AATXT_OPTION_FIELD_REGION_AZURE_TRANSLATE_INSTANCE) . '" value="' . esc_attr($translationRegion) . '" class="notRequired" />';
368 echo '</div>';
369
370 if ($translationApiKey && $translationEndpoint && $translationRegion):
371 echo '<div class="plugin-option type-azure">';
372 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_LANGUAGE_AZURE_TRANSLATE_INSTANCE) . '">' . esc_html__('Alt Text Language', 'auto-alt-text') . '</label>';
373 echo '<p class="description">' . esc_html__("Select the language in which the alt text should be written.", 'auto-alt-text') . '</p>';
374 $currentLanguage = get_option(Constants::AATXT_OPTION_FIELD_LANGUAGE_AZURE_TRANSLATE_INSTANCE);
375
376 try {
377 $supportedLanguages = (AzureTranslator::make())->supportedLanguages();
378 } catch (AzureTranslateInstanceException $e) {
379 $supportedLanguages = [
380 "en" => [
381 "name" => "English",
382 "nativeName" => "English",
383 "dir" => "ltr",
384 ]
385 ];
386 echo '<p style="color:red"><strong>' . esc_html($e->getMessage()) . '</strong></p>';
387 }
388
389 ?>
390 <select name="<?php echo esc_attr(Constants::AATXT_OPTION_FIELD_LANGUAGE_AZURE_TRANSLATE_INSTANCE); ?>"
391 id="<?php echo esc_attr(Constants::AATXT_OPTION_FIELD_LANGUAGE_AZURE_TRANSLATE_INSTANCE); ?>">
392 <?php
393 foreach ($supportedLanguages as $key => $language):
394 ?>
395 <option value="<?php echo esc_attr($key) ?>" <?php echo esc_attr(self::selected($currentLanguage, $key)); ?>><?php echo esc_html($language['name']); ?></option>
396 <?php
397 endforeach;
398 ?>
399 </select>
400
401 <?php
402
403 echo '</div>';
404 endif;
405
406 echo '<div class="plugin-option type-anthropic">';
407 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_API_KEY_ANTHROPIC) . '">' . esc_html__('Antrhopic API Key', 'auto-alt-text') . '</label>';
408 echo '<p class="description">' . esc_html__("Enter your API Key", 'auto-alt-text') . '</p>';
409 $apiKey = get_option(Constants::AATXT_OPTION_FIELD_API_KEY_ANTHROPIC);
410 echo '<input type="password" name="' . esc_attr(Constants::AATXT_OPTION_FIELD_API_KEY_ANTHROPIC) . '" value="' . esc_attr((Encryption::make())->decrypt($apiKey)) . '" />';
411 echo '</div>';
412
413 $anthropicModel = self::anthropicModel();
414
415 echo '<div class="plugin-option type-anthropic">';
416 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_MODEL_ANTHROPIC) . '">' . esc_html__('Model', 'auto-alt-text') . '</label>';
417
418 echo '<select name="' . esc_attr(Constants::AATXT_OPTION_FIELD_MODEL_ANTHROPIC) . '" id="' . esc_attr(Constants::AATXT_OPTION_FIELD_MODEL_ANTHROPIC) . '">';
419 foreach(Constants::AATXT_OPTION_FIELD_MODEL_ANTHROPIC_OPTIONS as $key => $value) {
420 echo '<option value="' . esc_attr($key) . '" ' . esc_attr(self::selected($anthropicModel, $key)) . '>' . esc_html($value) . '</option>';
421 }
422 echo '</select>';
423 echo '</div>';
424
425 echo '<div class="plugin-option type-anthropic">';
426 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_PROMPT_ANTHROPIC) . '">' . esc_html__('Prompt', 'auto-alt-text') . '</label>';
427 echo '<p class="description">' . esc_html__("Enter a specific and detailed prompt according to your needs.", 'auto-alt-text') . '</p>';
428 $defaultPrompt = sprintf(esc_html__("Act like an SEO expert and write an alt text of up to 125 characters for this image. Return only the complete alt text.", 'auto-alt-text'), Constants::AATXT_IMAGE_URL_TAG);
429 $prompt = get_option(Constants::AATXT_OPTION_FIELD_PROMPT_ANTHROPIC) ?: $defaultPrompt;
430 echo '<textarea name="' . esc_attr(Constants::AATXT_OPTION_FIELD_PROMPT_ANTHROPIC) . '" rows="5" cols="50">' . esc_textarea($prompt) . '</textarea>';
431 echo '</div>';
432
433 echo '<div class="plugin-option type-article-title type-attachment-title type-openai type-azure type-anthropic">';
434 echo '<label for="' . esc_attr(Constants::AATXT_OPTION_FIELD_PRESERVE_EXISTING_ALT_TEXT) . '">' . esc_html__('Keep existing alt text', 'auto-alt-text') . '</label>';
435 echo '<p class="description">' . esc_html__("If checked, the existing alt text of images will not be overwritten.", 'auto-alt-text') . '</p>';
436 $preserveAltText = get_option(Constants::AATXT_OPTION_FIELD_PRESERVE_EXISTING_ALT_TEXT);
437 echo '<input type="checkbox" name="' . esc_attr(Constants::AATXT_OPTION_FIELD_PRESERVE_EXISTING_ALT_TEXT) . '" value="1" class="notRequired" ' . checked(1, $preserveAltText, false) . ' />';
438 echo '</div>';
439
440 submit_button();
441 ?>
442 </form>
443 </div>
444 <?php
445 }
446
447 /**
448 * If option is selected return the selected attribute
449 * @param string $selectedValue
450 * @param string $inputValue
451 * @return string
452 */
453 public static function selected(string $selectedValue, string $inputValue): string
454 {
455 if (empty($selectedValue) && 'en' == $inputValue) {
456 return ' selected';
457 }
458 return $selectedValue == $inputValue ? ' selected' : '';
459 }
460
461
462 /**
463 * Register input fields and option settings
464 * @return void
465 */
466 public static function setupPluginOptions(): void
467 {
468 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_API_KEY_OPENAI);
469 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_PROMPT_OPENAI, [self::class, 'sanitizeTextArea']);
470 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_TYPOLOGY, [self::class, 'sanitizeText']);
471 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_MODEL_OPENAI, [self::class, 'sanitizeText']);
472 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_COMPUTER_VISION);
473 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_ENDPOINT_AZURE_COMPUTER_VISION, [self::class, 'sanitizeUrl']);
474 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_TRANSLATE_INSTANCE);
475 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_ENDPOINT_AZURE_TRANSLATE_INSTANCE, [self::class, 'sanitizeUrl']);
476 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_REGION_AZURE_TRANSLATE_INSTANCE, [self::class, 'sanitizeText']);
477 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_LANGUAGE_AZURE_TRANSLATE_INSTANCE, [self::class, 'sanitizeText']);
478 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_PRESERVE_EXISTING_ALT_TEXT);
479 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_API_KEY_ANTHROPIC);
480 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_PROMPT_ANTHROPIC, [self::class, 'sanitizeTextArea']);
481 register_setting('auto_alt_text_options', Constants::AATXT_OPTION_FIELD_MODEL_ANTHROPIC, [self::class, 'sanitizeText']);
482 }
483
484 /**
485 * @return string
486 */
487 public static function typology(): string
488 {
489 return get_option(Constants::AATXT_OPTION_FIELD_TYPOLOGY);
490 }
491
492 public static function openAiModel(): string
493 {
494 return get_option(Constants::AATXT_OPTION_FIELD_MODEL_OPENAI) ?: Constants::AATXT_GPT4O;
495 }
496
497 public static function anthropicModel(): string
498 {
499 return get_option(Constants::AATXT_OPTION_FIELD_MODEL_ANTHROPIC) ?: Constants::AATXT_CLAUDE_HAIKU_3_5;
500 }
501
502 /**
503 * @return string
504 */
505 public static function openAiPrompt(): string
506 {
507 return get_option(Constants::AATXT_OPTION_FIELD_PROMPT_OPENAI);
508 }
509
510 /**
511 * @return string
512 */
513 public static function anthropicPrompt(): string
514 {
515 return get_option(Constants::AATXT_OPTION_FIELD_PROMPT_ANTHROPIC);
516 }
517
518 /**
519 * @return string
520 */
521 public static function apiKeyOpenAI(): string
522 {
523 $apiKey = get_option(Constants::AATXT_OPTION_FIELD_API_KEY_OPENAI);
524 return (Encryption::make())->decrypt($apiKey);
525 }
526
527 /**
528 * @return string
529 */
530 public static function apiKeyAnthropic(): string
531 {
532 $apiKey = get_option(Constants::AATXT_OPTION_FIELD_API_KEY_ANTHROPIC);
533 return (Encryption::make())->decrypt($apiKey);
534 }
535
536 /**
537 * @return string
538 */
539 public static function apiKeyAzureComputerVision(): string
540 {
541 $apiKey = get_option(Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_COMPUTER_VISION);
542 return (Encryption::make())->decrypt($apiKey);
543 }
544
545 /**
546 * @return string
547 */
548 public static function endpointAzureComputerVision(): string
549 {
550 return get_option(Constants::AATXT_OPTION_FIELD_ENDPOINT_AZURE_COMPUTER_VISION);
551 }
552
553 /**
554 * @return string
555 */
556 public static function apiKeyAzureTranslateInstance(): string
557 {
558 $apiKey = get_option(Constants::AATXT_OPTION_FIELD_API_KEY_AZURE_TRANSLATE_INSTANCE);
559 return (Encryption::make())->decrypt($apiKey);
560 }
561
562 /**
563 * @return string
564 */
565 public static function endpointAzureTranslateInstance(): string
566 {
567 return get_option(Constants::AATXT_OPTION_FIELD_ENDPOINT_AZURE_TRANSLATE_INSTANCE);
568 }
569
570 /**
571 * @return string
572 */
573 public static function regionAzureTranslateInstance(): string
574 {
575 return get_option(Constants::AATXT_OPTION_FIELD_REGION_AZURE_TRANSLATE_INSTANCE);
576 }
577
578 /**
579 * @return string
580 */
581 public static function languageAzureTranslateInstance(): string
582 {
583 return get_option(Constants::AATXT_OPTION_FIELD_LANGUAGE_AZURE_TRANSLATE_INSTANCE) ?: 'en';
584 }
585
586 /**
587 * @return bool
588 */
589 public static function preserveExistingAltText(): bool
590 {
591 return get_option(Constants::AATXT_OPTION_FIELD_PRESERVE_EXISTING_ALT_TEXT);
592 }
593
594 public static function sanitizeUrl($input): string
595 {
596 return sanitize_url($input);
597 }
598
599 public static function sanitizeText($input): string
600 {
601 return sanitize_text_field($input);
602 }
603
604 public static function sanitizeTextArea($input): string
605 {
606 return sanitize_textarea_field($input);
607 }
608 }
609