Changeset 3485046
- Timestamp:
- 03/17/2026 07:00:13 PM (11 days ago)
- Location:
- alttext-ai
- Files:
-
- 18 edited
- 1 copied
-
tags/1.10.31 (copied) (copied from alttext-ai/trunk)
-
tags/1.10.31/README.txt (modified) (1 diff)
-
tags/1.10.31/admin/class-atai-settings.php (modified) (4 diffs)
-
tags/1.10.31/admin/partials/settings.php (modified) (6 diffs)
-
tags/1.10.31/atai.php (modified) (2 diffs)
-
tags/1.10.31/changelog.txt (modified) (1 diff)
-
tags/1.10.31/includes/class-atai-attachment.php (modified) (8 diffs)
-
tags/1.10.31/includes/class-atai-utility.php (modified) (2 diffs)
-
tags/1.10.31/includes/class-atai.php (modified) (1 diff)
-
tags/1.10.31/uninstall.php (modified) (1 diff)
-
trunk/README.txt (modified) (1 diff)
-
trunk/admin/class-atai-settings.php (modified) (4 diffs)
-
trunk/admin/partials/settings.php (modified) (6 diffs)
-
trunk/atai.php (modified) (2 diffs)
-
trunk/changelog.txt (modified) (1 diff)
-
trunk/includes/class-atai-attachment.php (modified) (8 diffs)
-
trunk/includes/class-atai-utility.php (modified) (2 diffs)
-
trunk/includes/class-atai.php (modified) (1 diff)
-
trunk/uninstall.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
alttext-ai/tags/1.10.31/README.txt
r3476576 r3485046 6 6 Requires at least: 4.7 7 7 Tested up to: 6.9 8 Stable tag: 1.10.3 08 Stable tag: 1.10.31 9 9 WC requires at least: 3.3 10 10 WC tested up to: 10.1 -
alttext-ai/tags/1.10.31/admin/class-atai-settings.php
r3476576 r3485046 373 373 register_setting( 374 374 'atai-settings', 375 'atai_wpml_enabled_languages', 376 array( 377 'sanitize_callback' => array( $this, 'sanitize_wpml_enabled_languages' ), 378 ) 379 ); 380 381 register_setting( 382 'atai-settings', 375 383 'atai_update_title', 376 384 array( … … 593 601 public function sanitize_yes_no_checkbox( $input ) { 594 602 return $input === 'yes' ? 'yes' : 'no'; 603 } 604 605 /** 606 * Sanitize the WPML enabled languages array. 607 * 608 * @since 1.10.31 609 * @access public 610 * 611 * @param mixed $input The submitted languages array. 612 * @return array Sanitized array of language codes. 613 */ 614 public function sanitize_wpml_enabled_languages( $input ) { 615 if ( null === $input || '' === $input ) { 616 return array(); 617 } 618 if ( ! is_array( $input ) ) { 619 return array(); 620 } 621 $active_languages = apply_filters( 'wpml_active_languages', NULL ); 622 $valid_codes = is_array( $active_languages ) ? array_keys( $active_languages ) : array(); 623 $sanitized = array_map( 'sanitize_text_field', $input ); 624 $sanitized = array_map( 'trim', $sanitized ); 625 $sanitized = array_filter( $sanitized, 'strlen' ); 626 $sanitized = array_values( array_unique( $sanitized ) ); 627 if ( ! empty( $valid_codes ) ) { 628 $sanitized = array_values( array_intersect( $sanitized, $valid_codes ) ); 629 } 630 return $sanitized; 631 } 632 633 /** 634 * Determine whether the current request is saving the plugin settings form. 635 * 636 * @since 1.10.31 637 * @access private 638 * 639 * @return bool 640 */ 641 private function is_atai_settings_submission() { 642 return isset( $_POST['option_page'], $_POST['action'] ) && 643 $_POST['option_page'] === 'atai-settings' && 644 $_POST['action'] === 'update'; 645 } 646 647 /** 648 * Preserve WPML enabled languages when the checklist is not present in the form. 649 * 650 * When the WPML section is hidden (e.g. Polylang-only site), the checkbox array 651 * won't be in $_POST and WordPress would overwrite the value. This hook preserves 652 * the old value unless the sentinel field confirms the checklist was rendered. 653 * 654 * @since 1.10.31 655 * @access public 656 * 657 * @param mixed $value The new value. 658 * @param mixed $old_value The old value. 659 * @param string $option The option name. 660 * @return mixed 661 */ 662 public function preserve_wpml_enabled_languages( $value, $old_value, $option ) { 663 if ( ! $this->is_atai_settings_submission() ) { 664 return $value; 665 } 666 667 if ( empty( $_POST['atai_wpml_enabled_languages_present'] ) ) { 668 return $old_value; 669 } 670 if ( ! isset( $_POST['atai_wpml_enabled_languages'] ) ) { 671 return array(); 672 } 673 return $value; 674 } 675 676 /** 677 * Determine whether this request is running on a subsite with network-wide settings locked. 678 * 679 * @since 1.10.31 680 * @access private 681 * 682 * @return bool 683 */ 684 private function is_network_settings_locked_subsite() { 685 return is_multisite() && ! is_main_site() && get_site_option( 'atai_network_all_settings' ) === 'yes'; 686 } 687 688 /** 689 * Determine whether the API key is locked on this subsite. 690 * 691 * @since 1.10.31 692 * @access private 693 * 694 * @return bool 695 */ 696 private function is_network_api_key_locked_subsite() { 697 return is_multisite() && ! is_main_site() && ( 698 get_site_option( 'atai_network_all_settings' ) === 'yes' || 699 get_site_option( 'atai_network_api_key' ) === 'yes' 700 ); 701 } 702 703 /** 704 * Return the settings that should follow network-wide sharing. 705 * 706 * Site-local options are intentionally excluded so subsites can keep their own 707 * runtime state where needed. 708 * 709 * @since 1.10.31 710 * @access private 711 * 712 * @return array 713 */ 714 private function get_network_controlled_option_defaults() { 715 return array( 716 'atai_api_key' => '', 717 'atai_lang' => 'en', 718 'atai_model_name' => '', 719 'atai_force_lang' => 'no', 720 'atai_update_title' => 'no', 721 'atai_update_caption' => 'no', 722 'atai_update_description' => 'no', 723 'atai_enabled' => 'yes', 724 'atai_skip_filenotfound' => 'no', 725 'atai_keywords' => 'yes', 726 'atai_keywords_title' => 'no', 727 'atai_ecomm' => 'yes', 728 'atai_ecomm_title' => 'no', 729 'atai_alt_prefix' => '', 730 'atai_alt_suffix' => '', 731 'atai_gpt_prompt' => '', 732 'atai_type_extensions' => '', 733 'atai_excluded_post_types' => '', 734 'atai_bulk_refresh_overwrite' => 'no', 735 'atai_bulk_refresh_external' => 'no', 736 'atai_refresh_src_attr' => 'src', 737 'atai_wp_generate_metadata' => 'no', 738 'atai_timeout' => '20', 739 'atai_public' => 'no', 740 'atai_no_credit_warning' => 'no', 741 'atai_admin_capability' => 'manage_options', 742 ); 743 } 744 745 /** 746 * Prevent subsites from overwriting network-controlled settings. 747 * 748 * @since 1.10.31 749 * @access public 750 * 751 * @param mixed $value The new value. 752 * @param string $option The option name. 753 * @param mixed $old_value The current value. 754 * @return mixed 755 */ 756 public function preserve_network_controlled_setting( $value, $option, $old_value ) { 757 if ( strpos( $option, 'atai_' ) !== 0 ) { 758 return $value; 759 } 760 761 if ( ! $this->is_network_settings_locked_subsite() ) { 762 return $value; 763 } 764 765 if ( ! array_key_exists( $option, $this->get_network_controlled_option_defaults() ) ) { 766 return $value; 767 } 768 769 return $old_value; 595 770 } 596 771 … … 700 875 */ 701 876 public function save_api_key( $api_key, $old_api_key ) { 877 if ( $this->is_network_api_key_locked_subsite() ) { 878 return $old_api_key; 879 } 880 702 881 $delete = is_null( $api_key ); 703 882 … … 770 949 } 771 950 772 // Settings with their defaults - prevents false from being stored for unset options 773 $settings_with_defaults = array( 774 'atai_api_key' => '', 775 'atai_lang' => 'en', 776 'atai_model_name' => '', 777 'atai_force_lang' => 'no', 778 'atai_update_title' => 'no', 779 'atai_update_caption' => 'no', 780 'atai_update_description' => 'no', 781 'atai_enabled' => 'yes', 782 'atai_skip_filenotfound' => 'no', 783 'atai_keywords' => 'yes', 784 'atai_keywords_title' => 'no', 785 'atai_ecomm' => 'yes', 786 'atai_ecomm_title' => 'no', 787 'atai_alt_prefix' => '', 788 'atai_alt_suffix' => '', 789 'atai_gpt_prompt' => '', 790 'atai_type_extensions' => '', 791 'atai_excluded_post_types' => '', 792 'atai_bulk_refresh_overwrite' => 'no', 793 'atai_bulk_refresh_external' => 'no', 794 'atai_refresh_src_attr' => 'src', 795 'atai_wp_generate_metadata' => 'no', 796 'atai_timeout' => '20', 797 'atai_public' => 'no', 798 'atai_no_credit_warning' => 'no', 799 'atai_admin_capability' => 'manage_options', 800 ); 951 // Settings with their defaults - prevents false from being stored for unset options. 952 // Site-local options are intentionally excluded here even when all settings are shared. 953 $settings_with_defaults = $this->get_network_controlled_option_defaults(); 801 954 802 955 // Create a network_settings array with values from the main site (with defaults) -
alttext-ai/tags/1.10.31/admin/partials/settings.php
r3476576 r3485046 37 37 // API key is locked when either network API key OR all settings are shared 38 38 $api_key_locked = $is_multisite && ! $is_main_site && ( $network_controls_api_key || $network_controls_all_settings ); 39 40 $show_force_lang_toggle = ATAI_Utility::has_multiple_languages(); 41 $show_wpml_language_selector = $show_force_lang_toggle && ATAI_Utility::has_wpml(); 42 $wpml_active_languages = $show_wpml_language_selector ? apply_filters( 'wpml_active_languages', null ) : array(); 43 $show_wpml_language_selector = $show_wpml_language_selector && is_array( $wpml_active_languages ) && count( $wpml_active_languages ) > 1; 44 $enabled_languages = $show_wpml_language_selector ? ATAI_Utility::get_setting( 'atai_wpml_enabled_languages', null ) : null; 45 $show_local_wpml_save = $settings_network_controlled && $show_wpml_language_selector; 39 46 ?> 40 47 … … 142 149 <?php do_settings_sections( 'atai-settings' ); ?> 143 150 144 <?php if ( ! $settings_network_controlled ) : ?>145 <input type="submit" name="submit" value=" Save Changes" class="atai-button blue mt-4 cursor-pointer appearance-none no-underline shadow-sm">151 <?php if ( ! $settings_network_controlled || $show_local_wpml_save ) : ?> 152 <input type="submit" name="submit" value="<?php echo esc_attr( $show_local_wpml_save ? __( 'Save Language Selection', 'alttext-ai' ) : __( 'Save Changes', 'alttext-ai' ) ); ?>" class="atai-button blue mt-4 cursor-pointer appearance-none no-underline shadow-sm <?php echo $show_local_wpml_save ? 'atai-local-setting-submit' : ''; ?>"> 146 153 <?php endif; ?> 147 154 <div class="mt-4 space-y-4 border-b-0 border-t border-solid divide-x-0 divide-y divide-solid sm:space-y-6 border-x-0 border-gray-900/10 divide-gray-900/10"> … … 262 269 ?> 263 270 </select> 264 <?php if ( ATAI_Utility::has_polylang() || ATAI_Utility::has_wpml()) : ?>271 <?php if ( $show_force_lang_toggle ) : ?> 265 272 <div class="ml-2 mt-4 flex relative gap-x-3"> 266 273 <div class="flex items-center h-6"> … … 277 284 <label for="atai_force_lang" class="text-gray-600"><?php esc_html_e( 'Always use this language, even if translations exist.', 'alttext-ai' ); ?></label> 278 285 </div> 286 </div> 287 <?php elseif ( ATAI_Utility::has_polylang() || ATAI_Utility::has_wpml() ) : ?> 288 <input type="hidden" name="atai_force_lang" value="<?php echo esc_attr( ATAI_Utility::get_setting( 'atai_force_lang', 'no' ) ); ?>"> 289 <?php endif; ?> 290 291 <?php if ( $show_wpml_language_selector ) : ?> 292 <div class="ml-2 mt-4"> 293 <input type="hidden" name="atai_wpml_enabled_languages_present" value="1"> 294 <p class="text-sm font-medium text-gray-700 mb-2"><?php esc_html_e( 'Generate alt text for these WPML languages:', 'alttext-ai' ); ?></p> 295 <?php if ( $show_local_wpml_save ) : ?> 296 <p class="mb-2 text-xs text-gray-500"><?php esc_html_e( 'This language filter is saved per site even when other settings are managed network-wide.', 'alttext-ai' ); ?></p> 297 <?php endif; ?> 298 <?php foreach ( $wpml_active_languages as $code => $lang_info ) : 299 $is_checked = ( null === $enabled_languages ) || in_array( $code, (array) $enabled_languages, true ); 300 ?> 301 <div class="flex items-center gap-x-2 mb-1"> 302 <input 303 type="checkbox" 304 id="atai_wpml_lang_<?php echo esc_attr( $code ); ?>" 305 name="atai_wpml_enabled_languages[]" 306 value="<?php echo esc_attr( $code ); ?>" 307 class="w-4 h-4 rounded border-gray-300 text-primary-600 focus:ring-primary-600" 308 <?php checked( $is_checked ); ?> 309 > 310 <label for="atai_wpml_lang_<?php echo esc_attr( $code ); ?>" class="text-sm text-gray-600"> 311 <?php 312 echo esc_html( $lang_info['native_name'] ); 313 if ( ! empty( $lang_info['translated_name'] ) && $lang_info['translated_name'] !== $lang_info['native_name'] ) { 314 echo ' (' . esc_html( $lang_info['translated_name'] ) . ')'; 315 } 316 ?> 317 </label> 318 </div> 319 <?php endforeach; ?> 320 <p class="mt-1 text-xs text-gray-500"><?php esc_html_e( 'Unchecked languages will be skipped when auto-generating translations.', 'alttext-ai' ); ?></p> 321 <?php if ( ATAI_Utility::get_setting( 'atai_force_lang' ) === 'yes' ) : ?> 322 <p class="mt-1 text-xs text-amber-600"><?php esc_html_e( 'Note: "Always use this language" is enabled, so all translations will use the selected language above.', 'alttext-ai' ); ?></p> 323 <?php endif; ?> 279 324 </div> 280 325 <?php endif; ?> … … 832 877 833 878 <div class="atai-settings-footer"> 834 <?php if ( ! $settings_network_controlled ) : ?>835 <input type="submit" name="submit" value=" Save Changes" class="atai-button blue cursor-pointer appearance-none no-underline shadow-sm">879 <?php if ( ! $settings_network_controlled || $show_local_wpml_save ) : ?> 880 <input type="submit" name="submit" value="<?php echo esc_attr( $show_local_wpml_save ? __( 'Save Language Selection', 'alttext-ai' ) : __( 'Save Changes', 'alttext-ai' ) ); ?>" class="atai-button blue cursor-pointer appearance-none no-underline shadow-sm <?php echo $show_local_wpml_save ? 'atai-local-setting-submit' : ''; ?>"> 836 881 <?php endif; ?> 837 882 <span class="atai-version">v<?php echo esc_html( ATAI_VERSION ); ?></span> … … 848 893 const inputs = form.querySelectorAll('input:not([type="hidden"]), select, textarea'); 849 894 inputs.forEach(function(input) { 895 if (input.matches('input[name="atai_wpml_enabled_languages[]"], .atai-local-setting-submit')) { 896 return; 897 } 850 898 input.disabled = true; 851 899 }); -
alttext-ai/tags/1.10.31/atai.php
r3476576 r3485046 16 16 * Plugin URI: https://alttext.ai/product 17 17 * Description: Automatically generate image alt text with AltText.ai. 18 * Version: 1.10.3 018 * Version: 1.10.31 19 19 * Author: AltText.ai 20 20 * Author URI: https://alttext.ai … … 34 34 * Current plugin version. 35 35 */ 36 define( 'ATAI_VERSION', '1.10.3 0' );36 define( 'ATAI_VERSION', '1.10.31' ); 37 37 38 38 /** -
alttext-ai/tags/1.10.31/changelog.txt
r3476576 r3485046 1 1 *** AltText.ai Changelog *** 2 3 2026-03-16 - version 1.10.31 4 * NEW: WPML language filter — choose which languages auto-generate alt text 5 * Improved: Network-controlled settings guard prevents subsites from overwriting shared options 2 6 3 7 2026-03-06 - version 1.10.30 -
alttext-ai/tags/1.10.31/includes/class-atai-attachment.php
r3466692 r3485046 1113 1113 } 1114 1114 1115 // Generate alt text for primary attachment 1116 $this->generate_alt( $attachment_id ); 1117 1118 // Process WPML translations if applicable 1115 // Generate alt text for primary attachment (skip if its language is excluded) 1116 if ( $this->should_auto_process_wpml_attachment( $attachment_id ) ) { 1117 $this->generate_alt( $attachment_id ); 1118 } 1119 1120 // Process WPML translations if applicable (has its own language filtering) 1119 1121 $this->process_wpml_translations( $attachment_id ); 1120 1122 1121 1123 // Process Polylang translations if applicable 1122 1124 $this->process_polylang_translations( $attachment_id ); 1125 } 1126 1127 /** 1128 * Get the saved WPML language selection for this request. 1129 * 1130 * @since 1.10.31 1131 * @access private 1132 * 1133 * @return array|null 1134 */ 1135 private function get_wpml_enabled_languages_selection() { 1136 $enabled_languages = ATAI_Utility::get_setting( 'atai_wpml_enabled_languages', null ); 1137 1138 return is_array( $enabled_languages ) ? $enabled_languages : null; 1139 } 1140 1141 /** 1142 * Filter active WPML languages against the saved per-site selection. 1143 * 1144 * Falls back to all active languages when the saved selection is stale 1145 * (for example, WPML languages were reconfigured after the option was saved). 1146 * 1147 * @since 1.10.31 1148 * @access private 1149 * 1150 * @param array $active_languages Active WPML languages keyed by language code. 1151 * @param bool $respect_enabled_languages Whether to apply the saved selection. 1152 * @return array 1153 */ 1154 private function filter_wpml_active_languages( $active_languages, $respect_enabled_languages = true ) { 1155 if ( ! $respect_enabled_languages || ! is_array( $active_languages ) || count( $active_languages ) <= 1 ) { 1156 return $active_languages; 1157 } 1158 1159 $enabled_languages = $this->get_wpml_enabled_languages_selection(); 1160 if ( ! is_array( $enabled_languages ) ) { 1161 return $active_languages; 1162 } 1163 1164 if ( empty( $enabled_languages ) ) { 1165 return array(); 1166 } 1167 1168 $filtered_languages = array_intersect_key( $active_languages, array_flip( $enabled_languages ) ); 1169 if ( empty( $filtered_languages ) ) { 1170 return $active_languages; 1171 } 1172 1173 return $filtered_languages; 1174 } 1175 1176 /** 1177 * Determine whether automatic processing should run for this attachment's WPML language. 1178 * 1179 * Manual single-image generation can still target any attachment directly; this 1180 * guard is only for automatic and bulk flows where unchecked languages should 1181 * skip the attachment entirely. 1182 * 1183 * @since 1.10.31 1184 * @access private 1185 * 1186 * @param int $attachment_id Attachment ID. 1187 * @return bool 1188 */ 1189 private function should_auto_process_wpml_attachment( $attachment_id ) { 1190 if ( ! ATAI_Utility::has_wpml() ) { 1191 return true; 1192 } 1193 1194 // If WPML no longer has multiple languages, ignore any stale filter 1195 $active_languages = apply_filters( 'wpml_active_languages', null ); 1196 if ( ! is_array( $active_languages ) || count( $active_languages ) <= 1 ) { 1197 return true; 1198 } 1199 1200 $active_languages = $this->filter_wpml_active_languages( $active_languages ); 1201 if ( empty( $active_languages ) ) { 1202 return false; 1203 } 1204 1205 $language_details = apply_filters( 'wpml_post_language_details', null, $attachment_id ); 1206 if ( ! is_array( $language_details ) || empty( $language_details['language_code'] ) ) { 1207 return true; 1208 } 1209 1210 return array_key_exists( $language_details['language_code'], $active_languages ); 1123 1211 } 1124 1212 … … 1135 1223 'processed_ids' => array(), 1136 1224 ); 1225 $respect_enabled_languages = true; 1226 1227 if ( array_key_exists( 'respect_wpml_enabled_languages', $options ) ) { 1228 $respect_enabled_languages = ! empty( $options['respect_wpml_enabled_languages'] ); 1229 unset( $options['respect_wpml_enabled_languages'] ); 1230 } 1137 1231 1138 1232 if ( ! ATAI_Utility::has_wpml() ) { … … 1142 1236 $active_languages = apply_filters( 'wpml_active_languages', NULL ); 1143 1237 if ( empty( $active_languages ) || ! is_array( $active_languages ) ) { 1238 return $results; 1239 } 1240 1241 $active_languages = $this->filter_wpml_active_languages( $active_languages, $respect_enabled_languages ); 1242 if ( empty( $active_languages ) ) { 1144 1243 return $results; 1145 1244 } … … 1445 1544 $reason_messages[] = sprintf(__('%d generation failures', 'alttext-ai'), $final_skip_reasons['generation_failed']); 1446 1545 } 1546 if ( isset( $final_skip_reasons['wpml_language_filtered'] ) && $final_skip_reasons['wpml_language_filtered'] > 0 ) { 1547 $reason_messages[] = sprintf(__('%d skipped by WPML language filter', 'alttext-ai'), $final_skip_reasons['wpml_language_filtered']); 1548 } 1447 1549 1448 1550 if ( ! empty( $reason_messages ) ) { … … 1521 1623 } 1522 1624 1625 if ( ++$loop_count >= $query_limit ) { 1626 break; 1627 } 1628 continue; 1629 } 1630 1631 if ( ! $this->should_auto_process_wpml_attachment( $attachment_id ) ) { 1632 $images_skipped++; 1633 $last_post_id = $attachment_id; 1634 $skip_reasons['wpml_language_filtered'] = ( $skip_reasons['wpml_language_filtered'] ?? 0 ) + 1; 1635 1636 if ( $mode === 'bulk-select' ) { 1637 $processed_ids[] = $attachment_id; 1638 } 1639 1523 1640 if ( ++$loop_count >= $query_limit ) { 1524 1641 break; … … 1704 1821 $this->generate_alt( $attachment_id ); 1705 1822 1706 // Process WPML translations 1707 $this->process_wpml_translations( $attachment_id ); 1823 // Process WPML translations without applying the automatic language filter. 1824 $this->process_wpml_translations( $attachment_id, array( 1825 'respect_wpml_enabled_languages' => false, 1826 ) ); 1708 1827 1709 1828 // Process Polylang translations … … 1768 1887 // Process WPML translations for successfully generated primary image 1769 1888 $wpml_results = $this->process_wpml_translations( $attachment_id, array( 1770 'keywords' => $keywords, 1889 'keywords' => $keywords, 1890 'respect_wpml_enabled_languages' => false, 1771 1891 ) ); 1772 1892 … … 2503 2623 } 2504 2624 2625 if ( ! $this->should_auto_process_wpml_attachment( $attachment_id ) ) { 2626 $last_post_id = $attachment_id; 2627 if ( ++$loop_count >= $query_limit ) { 2628 break; 2629 } 2630 continue; 2631 } 2632 2505 2633 $response = $this->generate_alt( $attachment_id ); 2506 2634 -
alttext-ai/tags/1.10.31/includes/class-atai-utility.php
r3466692 r3485046 289 289 290 290 /** 291 * Determine if multiple languages are configured in WPML or Polylang. 292 * 293 * Only returns true when WPML/Polylang is active AND has 2+ languages set up. 294 * Used to conditionally show the "force language" checkbox on the settings page. 295 * 296 * @since 1.10.31 297 * @access public 298 */ 299 public static function has_multiple_languages() { 300 if ( self::has_wpml() ) { 301 $active_languages = apply_filters( 'wpml_active_languages', NULL ); 302 return is_array( $active_languages ) && count( $active_languages ) > 1; 303 } 304 305 if ( self::has_polylang() && function_exists( 'pll_languages_list' ) ) { 306 $active_languages = pll_languages_list(); 307 return is_array( $active_languages ) && count( $active_languages ) > 1; 308 } 309 310 return false; 311 } 312 313 /** 291 314 * Determine if SmartCrawl is installed/active. 292 315 * … … 392 415 */ 393 416 public static function get_setting( $option_name, $default = false ) { 417 // WPML language selections are site-local even when network settings are shared, 418 // because each site can have a different active language set. 419 if ( $option_name === 'atai_wpml_enabled_languages' ) { 420 return get_option( $option_name, $default ); 421 } 422 394 423 // If not multisite, just get the regular option 395 424 if ( ! is_multisite() ) { -
alttext-ai/tags/1.10.31/includes/class-atai.php
r3466692 r3485046 214 214 215 215 $this->loader->add_filter( 'pre_update_option_atai_api_key', $settings, 'save_api_key', 10, 2 ); 216 $this->loader->add_filter( 'pre_update_option_atai_wpml_enabled_languages', $settings, 'preserve_wpml_enabled_languages', 10, 3 ); 217 $this->loader->add_filter( 'pre_update_option', $settings, 'preserve_network_controlled_setting', 10, 3 ); 216 218 $this->loader->add_filter( 'option_page_capability_atai-settings', $settings, 'filter_settings_capability' ); 217 219 -
alttext-ai/tags/1.10.31/uninstall.php
r3230517 r3485046 26 26 delete_option( 'atai_ecomm_title' ); 27 27 delete_option( 'atai_force_lang' ); 28 delete_option( 'atai_wpml_enabled_languages' ); 28 29 delete_option( 'atai_update_title' ); 29 30 delete_option( 'atai_update_caption' ); -
alttext-ai/trunk/README.txt
r3476576 r3485046 6 6 Requires at least: 4.7 7 7 Tested up to: 6.9 8 Stable tag: 1.10.3 08 Stable tag: 1.10.31 9 9 WC requires at least: 3.3 10 10 WC tested up to: 10.1 -
alttext-ai/trunk/admin/class-atai-settings.php
r3476576 r3485046 373 373 register_setting( 374 374 'atai-settings', 375 'atai_wpml_enabled_languages', 376 array( 377 'sanitize_callback' => array( $this, 'sanitize_wpml_enabled_languages' ), 378 ) 379 ); 380 381 register_setting( 382 'atai-settings', 375 383 'atai_update_title', 376 384 array( … … 593 601 public function sanitize_yes_no_checkbox( $input ) { 594 602 return $input === 'yes' ? 'yes' : 'no'; 603 } 604 605 /** 606 * Sanitize the WPML enabled languages array. 607 * 608 * @since 1.10.31 609 * @access public 610 * 611 * @param mixed $input The submitted languages array. 612 * @return array Sanitized array of language codes. 613 */ 614 public function sanitize_wpml_enabled_languages( $input ) { 615 if ( null === $input || '' === $input ) { 616 return array(); 617 } 618 if ( ! is_array( $input ) ) { 619 return array(); 620 } 621 $active_languages = apply_filters( 'wpml_active_languages', NULL ); 622 $valid_codes = is_array( $active_languages ) ? array_keys( $active_languages ) : array(); 623 $sanitized = array_map( 'sanitize_text_field', $input ); 624 $sanitized = array_map( 'trim', $sanitized ); 625 $sanitized = array_filter( $sanitized, 'strlen' ); 626 $sanitized = array_values( array_unique( $sanitized ) ); 627 if ( ! empty( $valid_codes ) ) { 628 $sanitized = array_values( array_intersect( $sanitized, $valid_codes ) ); 629 } 630 return $sanitized; 631 } 632 633 /** 634 * Determine whether the current request is saving the plugin settings form. 635 * 636 * @since 1.10.31 637 * @access private 638 * 639 * @return bool 640 */ 641 private function is_atai_settings_submission() { 642 return isset( $_POST['option_page'], $_POST['action'] ) && 643 $_POST['option_page'] === 'atai-settings' && 644 $_POST['action'] === 'update'; 645 } 646 647 /** 648 * Preserve WPML enabled languages when the checklist is not present in the form. 649 * 650 * When the WPML section is hidden (e.g. Polylang-only site), the checkbox array 651 * won't be in $_POST and WordPress would overwrite the value. This hook preserves 652 * the old value unless the sentinel field confirms the checklist was rendered. 653 * 654 * @since 1.10.31 655 * @access public 656 * 657 * @param mixed $value The new value. 658 * @param mixed $old_value The old value. 659 * @param string $option The option name. 660 * @return mixed 661 */ 662 public function preserve_wpml_enabled_languages( $value, $old_value, $option ) { 663 if ( ! $this->is_atai_settings_submission() ) { 664 return $value; 665 } 666 667 if ( empty( $_POST['atai_wpml_enabled_languages_present'] ) ) { 668 return $old_value; 669 } 670 if ( ! isset( $_POST['atai_wpml_enabled_languages'] ) ) { 671 return array(); 672 } 673 return $value; 674 } 675 676 /** 677 * Determine whether this request is running on a subsite with network-wide settings locked. 678 * 679 * @since 1.10.31 680 * @access private 681 * 682 * @return bool 683 */ 684 private function is_network_settings_locked_subsite() { 685 return is_multisite() && ! is_main_site() && get_site_option( 'atai_network_all_settings' ) === 'yes'; 686 } 687 688 /** 689 * Determine whether the API key is locked on this subsite. 690 * 691 * @since 1.10.31 692 * @access private 693 * 694 * @return bool 695 */ 696 private function is_network_api_key_locked_subsite() { 697 return is_multisite() && ! is_main_site() && ( 698 get_site_option( 'atai_network_all_settings' ) === 'yes' || 699 get_site_option( 'atai_network_api_key' ) === 'yes' 700 ); 701 } 702 703 /** 704 * Return the settings that should follow network-wide sharing. 705 * 706 * Site-local options are intentionally excluded so subsites can keep their own 707 * runtime state where needed. 708 * 709 * @since 1.10.31 710 * @access private 711 * 712 * @return array 713 */ 714 private function get_network_controlled_option_defaults() { 715 return array( 716 'atai_api_key' => '', 717 'atai_lang' => 'en', 718 'atai_model_name' => '', 719 'atai_force_lang' => 'no', 720 'atai_update_title' => 'no', 721 'atai_update_caption' => 'no', 722 'atai_update_description' => 'no', 723 'atai_enabled' => 'yes', 724 'atai_skip_filenotfound' => 'no', 725 'atai_keywords' => 'yes', 726 'atai_keywords_title' => 'no', 727 'atai_ecomm' => 'yes', 728 'atai_ecomm_title' => 'no', 729 'atai_alt_prefix' => '', 730 'atai_alt_suffix' => '', 731 'atai_gpt_prompt' => '', 732 'atai_type_extensions' => '', 733 'atai_excluded_post_types' => '', 734 'atai_bulk_refresh_overwrite' => 'no', 735 'atai_bulk_refresh_external' => 'no', 736 'atai_refresh_src_attr' => 'src', 737 'atai_wp_generate_metadata' => 'no', 738 'atai_timeout' => '20', 739 'atai_public' => 'no', 740 'atai_no_credit_warning' => 'no', 741 'atai_admin_capability' => 'manage_options', 742 ); 743 } 744 745 /** 746 * Prevent subsites from overwriting network-controlled settings. 747 * 748 * @since 1.10.31 749 * @access public 750 * 751 * @param mixed $value The new value. 752 * @param string $option The option name. 753 * @param mixed $old_value The current value. 754 * @return mixed 755 */ 756 public function preserve_network_controlled_setting( $value, $option, $old_value ) { 757 if ( strpos( $option, 'atai_' ) !== 0 ) { 758 return $value; 759 } 760 761 if ( ! $this->is_network_settings_locked_subsite() ) { 762 return $value; 763 } 764 765 if ( ! array_key_exists( $option, $this->get_network_controlled_option_defaults() ) ) { 766 return $value; 767 } 768 769 return $old_value; 595 770 } 596 771 … … 700 875 */ 701 876 public function save_api_key( $api_key, $old_api_key ) { 877 if ( $this->is_network_api_key_locked_subsite() ) { 878 return $old_api_key; 879 } 880 702 881 $delete = is_null( $api_key ); 703 882 … … 770 949 } 771 950 772 // Settings with their defaults - prevents false from being stored for unset options 773 $settings_with_defaults = array( 774 'atai_api_key' => '', 775 'atai_lang' => 'en', 776 'atai_model_name' => '', 777 'atai_force_lang' => 'no', 778 'atai_update_title' => 'no', 779 'atai_update_caption' => 'no', 780 'atai_update_description' => 'no', 781 'atai_enabled' => 'yes', 782 'atai_skip_filenotfound' => 'no', 783 'atai_keywords' => 'yes', 784 'atai_keywords_title' => 'no', 785 'atai_ecomm' => 'yes', 786 'atai_ecomm_title' => 'no', 787 'atai_alt_prefix' => '', 788 'atai_alt_suffix' => '', 789 'atai_gpt_prompt' => '', 790 'atai_type_extensions' => '', 791 'atai_excluded_post_types' => '', 792 'atai_bulk_refresh_overwrite' => 'no', 793 'atai_bulk_refresh_external' => 'no', 794 'atai_refresh_src_attr' => 'src', 795 'atai_wp_generate_metadata' => 'no', 796 'atai_timeout' => '20', 797 'atai_public' => 'no', 798 'atai_no_credit_warning' => 'no', 799 'atai_admin_capability' => 'manage_options', 800 ); 951 // Settings with their defaults - prevents false from being stored for unset options. 952 // Site-local options are intentionally excluded here even when all settings are shared. 953 $settings_with_defaults = $this->get_network_controlled_option_defaults(); 801 954 802 955 // Create a network_settings array with values from the main site (with defaults) -
alttext-ai/trunk/admin/partials/settings.php
r3476576 r3485046 37 37 // API key is locked when either network API key OR all settings are shared 38 38 $api_key_locked = $is_multisite && ! $is_main_site && ( $network_controls_api_key || $network_controls_all_settings ); 39 40 $show_force_lang_toggle = ATAI_Utility::has_multiple_languages(); 41 $show_wpml_language_selector = $show_force_lang_toggle && ATAI_Utility::has_wpml(); 42 $wpml_active_languages = $show_wpml_language_selector ? apply_filters( 'wpml_active_languages', null ) : array(); 43 $show_wpml_language_selector = $show_wpml_language_selector && is_array( $wpml_active_languages ) && count( $wpml_active_languages ) > 1; 44 $enabled_languages = $show_wpml_language_selector ? ATAI_Utility::get_setting( 'atai_wpml_enabled_languages', null ) : null; 45 $show_local_wpml_save = $settings_network_controlled && $show_wpml_language_selector; 39 46 ?> 40 47 … … 142 149 <?php do_settings_sections( 'atai-settings' ); ?> 143 150 144 <?php if ( ! $settings_network_controlled ) : ?>145 <input type="submit" name="submit" value=" Save Changes" class="atai-button blue mt-4 cursor-pointer appearance-none no-underline shadow-sm">151 <?php if ( ! $settings_network_controlled || $show_local_wpml_save ) : ?> 152 <input type="submit" name="submit" value="<?php echo esc_attr( $show_local_wpml_save ? __( 'Save Language Selection', 'alttext-ai' ) : __( 'Save Changes', 'alttext-ai' ) ); ?>" class="atai-button blue mt-4 cursor-pointer appearance-none no-underline shadow-sm <?php echo $show_local_wpml_save ? 'atai-local-setting-submit' : ''; ?>"> 146 153 <?php endif; ?> 147 154 <div class="mt-4 space-y-4 border-b-0 border-t border-solid divide-x-0 divide-y divide-solid sm:space-y-6 border-x-0 border-gray-900/10 divide-gray-900/10"> … … 262 269 ?> 263 270 </select> 264 <?php if ( ATAI_Utility::has_polylang() || ATAI_Utility::has_wpml()) : ?>271 <?php if ( $show_force_lang_toggle ) : ?> 265 272 <div class="ml-2 mt-4 flex relative gap-x-3"> 266 273 <div class="flex items-center h-6"> … … 277 284 <label for="atai_force_lang" class="text-gray-600"><?php esc_html_e( 'Always use this language, even if translations exist.', 'alttext-ai' ); ?></label> 278 285 </div> 286 </div> 287 <?php elseif ( ATAI_Utility::has_polylang() || ATAI_Utility::has_wpml() ) : ?> 288 <input type="hidden" name="atai_force_lang" value="<?php echo esc_attr( ATAI_Utility::get_setting( 'atai_force_lang', 'no' ) ); ?>"> 289 <?php endif; ?> 290 291 <?php if ( $show_wpml_language_selector ) : ?> 292 <div class="ml-2 mt-4"> 293 <input type="hidden" name="atai_wpml_enabled_languages_present" value="1"> 294 <p class="text-sm font-medium text-gray-700 mb-2"><?php esc_html_e( 'Generate alt text for these WPML languages:', 'alttext-ai' ); ?></p> 295 <?php if ( $show_local_wpml_save ) : ?> 296 <p class="mb-2 text-xs text-gray-500"><?php esc_html_e( 'This language filter is saved per site even when other settings are managed network-wide.', 'alttext-ai' ); ?></p> 297 <?php endif; ?> 298 <?php foreach ( $wpml_active_languages as $code => $lang_info ) : 299 $is_checked = ( null === $enabled_languages ) || in_array( $code, (array) $enabled_languages, true ); 300 ?> 301 <div class="flex items-center gap-x-2 mb-1"> 302 <input 303 type="checkbox" 304 id="atai_wpml_lang_<?php echo esc_attr( $code ); ?>" 305 name="atai_wpml_enabled_languages[]" 306 value="<?php echo esc_attr( $code ); ?>" 307 class="w-4 h-4 rounded border-gray-300 text-primary-600 focus:ring-primary-600" 308 <?php checked( $is_checked ); ?> 309 > 310 <label for="atai_wpml_lang_<?php echo esc_attr( $code ); ?>" class="text-sm text-gray-600"> 311 <?php 312 echo esc_html( $lang_info['native_name'] ); 313 if ( ! empty( $lang_info['translated_name'] ) && $lang_info['translated_name'] !== $lang_info['native_name'] ) { 314 echo ' (' . esc_html( $lang_info['translated_name'] ) . ')'; 315 } 316 ?> 317 </label> 318 </div> 319 <?php endforeach; ?> 320 <p class="mt-1 text-xs text-gray-500"><?php esc_html_e( 'Unchecked languages will be skipped when auto-generating translations.', 'alttext-ai' ); ?></p> 321 <?php if ( ATAI_Utility::get_setting( 'atai_force_lang' ) === 'yes' ) : ?> 322 <p class="mt-1 text-xs text-amber-600"><?php esc_html_e( 'Note: "Always use this language" is enabled, so all translations will use the selected language above.', 'alttext-ai' ); ?></p> 323 <?php endif; ?> 279 324 </div> 280 325 <?php endif; ?> … … 832 877 833 878 <div class="atai-settings-footer"> 834 <?php if ( ! $settings_network_controlled ) : ?>835 <input type="submit" name="submit" value=" Save Changes" class="atai-button blue cursor-pointer appearance-none no-underline shadow-sm">879 <?php if ( ! $settings_network_controlled || $show_local_wpml_save ) : ?> 880 <input type="submit" name="submit" value="<?php echo esc_attr( $show_local_wpml_save ? __( 'Save Language Selection', 'alttext-ai' ) : __( 'Save Changes', 'alttext-ai' ) ); ?>" class="atai-button blue cursor-pointer appearance-none no-underline shadow-sm <?php echo $show_local_wpml_save ? 'atai-local-setting-submit' : ''; ?>"> 836 881 <?php endif; ?> 837 882 <span class="atai-version">v<?php echo esc_html( ATAI_VERSION ); ?></span> … … 848 893 const inputs = form.querySelectorAll('input:not([type="hidden"]), select, textarea'); 849 894 inputs.forEach(function(input) { 895 if (input.matches('input[name="atai_wpml_enabled_languages[]"], .atai-local-setting-submit')) { 896 return; 897 } 850 898 input.disabled = true; 851 899 }); -
alttext-ai/trunk/atai.php
r3476576 r3485046 16 16 * Plugin URI: https://alttext.ai/product 17 17 * Description: Automatically generate image alt text with AltText.ai. 18 * Version: 1.10.3 018 * Version: 1.10.31 19 19 * Author: AltText.ai 20 20 * Author URI: https://alttext.ai … … 34 34 * Current plugin version. 35 35 */ 36 define( 'ATAI_VERSION', '1.10.3 0' );36 define( 'ATAI_VERSION', '1.10.31' ); 37 37 38 38 /** -
alttext-ai/trunk/changelog.txt
r3476576 r3485046 1 1 *** AltText.ai Changelog *** 2 3 2026-03-16 - version 1.10.31 4 * NEW: WPML language filter — choose which languages auto-generate alt text 5 * Improved: Network-controlled settings guard prevents subsites from overwriting shared options 2 6 3 7 2026-03-06 - version 1.10.30 -
alttext-ai/trunk/includes/class-atai-attachment.php
r3466692 r3485046 1113 1113 } 1114 1114 1115 // Generate alt text for primary attachment 1116 $this->generate_alt( $attachment_id ); 1117 1118 // Process WPML translations if applicable 1115 // Generate alt text for primary attachment (skip if its language is excluded) 1116 if ( $this->should_auto_process_wpml_attachment( $attachment_id ) ) { 1117 $this->generate_alt( $attachment_id ); 1118 } 1119 1120 // Process WPML translations if applicable (has its own language filtering) 1119 1121 $this->process_wpml_translations( $attachment_id ); 1120 1122 1121 1123 // Process Polylang translations if applicable 1122 1124 $this->process_polylang_translations( $attachment_id ); 1125 } 1126 1127 /** 1128 * Get the saved WPML language selection for this request. 1129 * 1130 * @since 1.10.31 1131 * @access private 1132 * 1133 * @return array|null 1134 */ 1135 private function get_wpml_enabled_languages_selection() { 1136 $enabled_languages = ATAI_Utility::get_setting( 'atai_wpml_enabled_languages', null ); 1137 1138 return is_array( $enabled_languages ) ? $enabled_languages : null; 1139 } 1140 1141 /** 1142 * Filter active WPML languages against the saved per-site selection. 1143 * 1144 * Falls back to all active languages when the saved selection is stale 1145 * (for example, WPML languages were reconfigured after the option was saved). 1146 * 1147 * @since 1.10.31 1148 * @access private 1149 * 1150 * @param array $active_languages Active WPML languages keyed by language code. 1151 * @param bool $respect_enabled_languages Whether to apply the saved selection. 1152 * @return array 1153 */ 1154 private function filter_wpml_active_languages( $active_languages, $respect_enabled_languages = true ) { 1155 if ( ! $respect_enabled_languages || ! is_array( $active_languages ) || count( $active_languages ) <= 1 ) { 1156 return $active_languages; 1157 } 1158 1159 $enabled_languages = $this->get_wpml_enabled_languages_selection(); 1160 if ( ! is_array( $enabled_languages ) ) { 1161 return $active_languages; 1162 } 1163 1164 if ( empty( $enabled_languages ) ) { 1165 return array(); 1166 } 1167 1168 $filtered_languages = array_intersect_key( $active_languages, array_flip( $enabled_languages ) ); 1169 if ( empty( $filtered_languages ) ) { 1170 return $active_languages; 1171 } 1172 1173 return $filtered_languages; 1174 } 1175 1176 /** 1177 * Determine whether automatic processing should run for this attachment's WPML language. 1178 * 1179 * Manual single-image generation can still target any attachment directly; this 1180 * guard is only for automatic and bulk flows where unchecked languages should 1181 * skip the attachment entirely. 1182 * 1183 * @since 1.10.31 1184 * @access private 1185 * 1186 * @param int $attachment_id Attachment ID. 1187 * @return bool 1188 */ 1189 private function should_auto_process_wpml_attachment( $attachment_id ) { 1190 if ( ! ATAI_Utility::has_wpml() ) { 1191 return true; 1192 } 1193 1194 // If WPML no longer has multiple languages, ignore any stale filter 1195 $active_languages = apply_filters( 'wpml_active_languages', null ); 1196 if ( ! is_array( $active_languages ) || count( $active_languages ) <= 1 ) { 1197 return true; 1198 } 1199 1200 $active_languages = $this->filter_wpml_active_languages( $active_languages ); 1201 if ( empty( $active_languages ) ) { 1202 return false; 1203 } 1204 1205 $language_details = apply_filters( 'wpml_post_language_details', null, $attachment_id ); 1206 if ( ! is_array( $language_details ) || empty( $language_details['language_code'] ) ) { 1207 return true; 1208 } 1209 1210 return array_key_exists( $language_details['language_code'], $active_languages ); 1123 1211 } 1124 1212 … … 1135 1223 'processed_ids' => array(), 1136 1224 ); 1225 $respect_enabled_languages = true; 1226 1227 if ( array_key_exists( 'respect_wpml_enabled_languages', $options ) ) { 1228 $respect_enabled_languages = ! empty( $options['respect_wpml_enabled_languages'] ); 1229 unset( $options['respect_wpml_enabled_languages'] ); 1230 } 1137 1231 1138 1232 if ( ! ATAI_Utility::has_wpml() ) { … … 1142 1236 $active_languages = apply_filters( 'wpml_active_languages', NULL ); 1143 1237 if ( empty( $active_languages ) || ! is_array( $active_languages ) ) { 1238 return $results; 1239 } 1240 1241 $active_languages = $this->filter_wpml_active_languages( $active_languages, $respect_enabled_languages ); 1242 if ( empty( $active_languages ) ) { 1144 1243 return $results; 1145 1244 } … … 1445 1544 $reason_messages[] = sprintf(__('%d generation failures', 'alttext-ai'), $final_skip_reasons['generation_failed']); 1446 1545 } 1546 if ( isset( $final_skip_reasons['wpml_language_filtered'] ) && $final_skip_reasons['wpml_language_filtered'] > 0 ) { 1547 $reason_messages[] = sprintf(__('%d skipped by WPML language filter', 'alttext-ai'), $final_skip_reasons['wpml_language_filtered']); 1548 } 1447 1549 1448 1550 if ( ! empty( $reason_messages ) ) { … … 1521 1623 } 1522 1624 1625 if ( ++$loop_count >= $query_limit ) { 1626 break; 1627 } 1628 continue; 1629 } 1630 1631 if ( ! $this->should_auto_process_wpml_attachment( $attachment_id ) ) { 1632 $images_skipped++; 1633 $last_post_id = $attachment_id; 1634 $skip_reasons['wpml_language_filtered'] = ( $skip_reasons['wpml_language_filtered'] ?? 0 ) + 1; 1635 1636 if ( $mode === 'bulk-select' ) { 1637 $processed_ids[] = $attachment_id; 1638 } 1639 1523 1640 if ( ++$loop_count >= $query_limit ) { 1524 1641 break; … … 1704 1821 $this->generate_alt( $attachment_id ); 1705 1822 1706 // Process WPML translations 1707 $this->process_wpml_translations( $attachment_id ); 1823 // Process WPML translations without applying the automatic language filter. 1824 $this->process_wpml_translations( $attachment_id, array( 1825 'respect_wpml_enabled_languages' => false, 1826 ) ); 1708 1827 1709 1828 // Process Polylang translations … … 1768 1887 // Process WPML translations for successfully generated primary image 1769 1888 $wpml_results = $this->process_wpml_translations( $attachment_id, array( 1770 'keywords' => $keywords, 1889 'keywords' => $keywords, 1890 'respect_wpml_enabled_languages' => false, 1771 1891 ) ); 1772 1892 … … 2503 2623 } 2504 2624 2625 if ( ! $this->should_auto_process_wpml_attachment( $attachment_id ) ) { 2626 $last_post_id = $attachment_id; 2627 if ( ++$loop_count >= $query_limit ) { 2628 break; 2629 } 2630 continue; 2631 } 2632 2505 2633 $response = $this->generate_alt( $attachment_id ); 2506 2634 -
alttext-ai/trunk/includes/class-atai-utility.php
r3466692 r3485046 289 289 290 290 /** 291 * Determine if multiple languages are configured in WPML or Polylang. 292 * 293 * Only returns true when WPML/Polylang is active AND has 2+ languages set up. 294 * Used to conditionally show the "force language" checkbox on the settings page. 295 * 296 * @since 1.10.31 297 * @access public 298 */ 299 public static function has_multiple_languages() { 300 if ( self::has_wpml() ) { 301 $active_languages = apply_filters( 'wpml_active_languages', NULL ); 302 return is_array( $active_languages ) && count( $active_languages ) > 1; 303 } 304 305 if ( self::has_polylang() && function_exists( 'pll_languages_list' ) ) { 306 $active_languages = pll_languages_list(); 307 return is_array( $active_languages ) && count( $active_languages ) > 1; 308 } 309 310 return false; 311 } 312 313 /** 291 314 * Determine if SmartCrawl is installed/active. 292 315 * … … 392 415 */ 393 416 public static function get_setting( $option_name, $default = false ) { 417 // WPML language selections are site-local even when network settings are shared, 418 // because each site can have a different active language set. 419 if ( $option_name === 'atai_wpml_enabled_languages' ) { 420 return get_option( $option_name, $default ); 421 } 422 394 423 // If not multisite, just get the regular option 395 424 if ( ! is_multisite() ) { -
alttext-ai/trunk/includes/class-atai.php
r3466692 r3485046 214 214 215 215 $this->loader->add_filter( 'pre_update_option_atai_api_key', $settings, 'save_api_key', 10, 2 ); 216 $this->loader->add_filter( 'pre_update_option_atai_wpml_enabled_languages', $settings, 'preserve_wpml_enabled_languages', 10, 3 ); 217 $this->loader->add_filter( 'pre_update_option', $settings, 'preserve_network_controlled_setting', 10, 3 ); 216 218 $this->loader->add_filter( 'option_page_capability_atai-settings', $settings, 'filter_settings_capability' ); 217 219 -
alttext-ai/trunk/uninstall.php
r3230517 r3485046 26 26 delete_option( 'atai_ecomm_title' ); 27 27 delete_option( 'atai_force_lang' ); 28 delete_option( 'atai_wpml_enabled_languages' ); 28 29 delete_option( 'atai_update_title' ); 29 30 delete_option( 'atai_update_caption' );
Note: See TracChangeset
for help on using the changeset viewer.