is_wpml = true; $this->is_multilang = true; } // PolyLang if(defined('POLYLANG_VERSION') && function_exists('pll_default_language')){ $this->is_polylang = true; $this->is_multilang = true; } if($this->is_multilang){ add_action('acf/init', array($this, 'init'), 99); } } function init(){ // Check setting if(!acf_get_setting('acfe/modules/multilang')) return; // Polylang specific if($this->is_polylang){ // Default/Current Language $dl = pll_default_language('locale'); $cl = pll_current_language('locale'); // Update settings acf_update_setting('default_language', $dl); acf_update_setting('current_language', $cl); add_filter('acf/pre_load_reference', array($this, 'polylang_preload_reference'), 10, 3); add_filter('acf/pre_load_value', array($this, 'polylang_preload_value'), 10, 3); } // Options Page Message add_action('acf/options_page/submitbox_before_major_actions', array($this, 'options_page_message')); // ACF Options Post ID add_filter('acf/validate_post_id', array($this, 'set_options_post_id'), 99, 2); } function polylang_preload_reference($null, $field_name, $post_id){ // Validate post id $original_post_id = $this->polylang_validate_preload_post_id($post_id); if(!$original_post_id) return $null; $reference = acf_get_metadata($post_id, $field_name, true); if($reference !== null) return $null; return acf_get_metadata($original_post_id, $field_name, true); } function polylang_preload_value($null, $post_id, $field){ // Validate post id $original_post_id = $this->polylang_validate_preload_post_id($post_id); if(!$original_post_id) return $null; // Get field name. $field_name = $field['name']; // Check store. $store = acf_get_store('values'); if($store->has("$post_id:$field_name")) return $null; // Load value from database. $value = acf_get_metadata($post_id, $field_name); // Use field's default_value if no meta was found. if($value !== null) return $null; return acf_get_value($original_post_id, $field); } function polylang_validate_preload_post_id($post_id){ // Bail early if admin screen if(is_admin() || !is_string($post_id)) return false; // Get post id info $data = acf_get_post_id_info($post_id); // Bail early if post id isn't an option type if($data['type'] !== 'option') return false; // Bail early if not localized if(!$this->is_localized($post_id)) return false; $original_post_id = preg_replace( '/([_\-][A-Za-z]{2}_[A-Za-z]{2})$/', '', $post_id); // Check the regex if($original_post_id === $post_id) return false; // Bail early if no Options Page found with that post id if(!$this->is_options_page($original_post_id)) return false; return $original_post_id; } /** * WPML * https://wpml.org/documentation/support/wpml-coding-api/wpml-hooks-reference/ */ function wpml_get_languages($pluck = '', $type = 'all'){ // Vars $languages = array(); $pluck = $pluck === 'locale' ? 'default_locale' : $pluck; switch($type){ // Active case 'active': // https://wpml.org/wpml-hook/wpml_active_languages/ $languages = apply_filters('wpml_active_languages', null, array('skip_missing' => 0)); // Set locale as key $_languages = $languages; $languages = array(); foreach($_languages as $lang){ $languages[ $lang['default_locale'] ] = $lang; } if($pluck) $languages = wp_list_pluck($languages, $pluck, true); return $languages; // All case '': case 'all': // https://wpml.org/wpml-hook/wpml_active_languages/ $languages = apply_filters('wpml_active_languages', null, array('skip_missing' => 0)); $languages = wp_list_pluck($languages, 'code', 'default_locale'); // Default Languages $_languages = icl_get_languages_locales(); $_languages = array_flip($_languages); if(!empty($_languages)){ $languages = array_merge($languages, $_languages); $languages = array_unique($languages); } if($pluck) $languages = $pluck === 'code' ? array_values($_languages) : array_keys($_languages); return $languages; } return $languages; } /** * PolyLang * https://polylang.pro/doc/filter-reference/ * https://polylang.pro/doc/developpers-how-to/ * https://polylang.pro/doc-category/developers/ * https://polylang.wordpress.com/documentation/documentation-for-developers/general/ * https://polylang.wordpress.com/documentation/documentation-for-developers/functions-reference/ */ function polylang_get_languages($pluck = '', $type = 'all'){ // Vars $languages = array(); switch($type){ // Active case 'active': // Convert pluck $pluck = $pluck === 'code' ? 'slug' : $pluck; // https://polylang.wordpress.com/documentation/documentation-for-developers/functions-reference/ $languages = pll_languages_list(array( 'hide_empty' => false, 'fields' => $pluck )); return $languages; // All case '': case 'all': $languages = PLL_Settings::get_predefined_languages(); if($pluck) $languages = wp_list_pluck($languages, $pluck, true); return $languages; } return $languages; } /** * ACF Options Post ID */ function set_options_post_id($post_id, $original_post_id){ // Bail early if original post id is 'options' ||'option' if(!is_string($post_id)) return $post_id; $data = acf_get_post_id_info($post_id); // Bail early if post id isn't an option type if($data['type'] !== 'option') return $post_id; // Options Exception // $post_id already translated during the native acf/validate_post_id if(in_array($original_post_id, array('options', 'option'))){ // Exclude filter $exclude = apply_filters('acfe/modules/multilang/exclude_options', array()); if(in_array('options', $exclude)){ return 'options'; } return $post_id; } // Bail early if no Options Page found with that post id if(!$this->is_options_page($post_id)) return $post_id; // Bail early if already localized: 'my-options_en_US' if($this->is_localized($post_id)) return $post_id; // Append current language to post id $dl = acf_get_setting('default_language'); $cl = acf_get_setting('current_language'); // Add Language if($cl && $cl !== $dl){ $post_id .= '_' . $cl; } return $post_id; } function is_localized($post_id){ // Check if post id ends with '-en_US' || '_en_US' || '-en' || '_en' // https://regex101.com/r/oMsyeL/4 preg_match('/(?P[_\-][A-Za-z]{2}_[A-Za-z]{2})$|(?P[_\-][A-Za-z]{2})$/', $post_id, $matches); if(empty($matches)) return false; // Cleanup matches $lang = array(); foreach($matches as $key => $val){ if(is_int($key) || empty($val)) continue; $lang = array( 'type' => $key, 'lang' => strtolower(substr($val, 1)), // Lowercase + Remove the first '_' ); } if(empty($lang)) return false; // Get WPML/Polylang Languages List $languages = $this->get_languages($lang['type']); $languages = array_map('strtolower', $languages); // Compare Matches vs WPML/Polylang Languages List return in_array($lang['lang'], $languages); } function is_options_page($post_id){ // Get Options Pages if($this->options_pages === false){ // Get ACF Options Pages $options_pages = acf_get_array(acf_get_options_pages()); $list = wp_list_pluck($options_pages, 'post_id', true); // Add 'Post Types List' location $post_types = acf_get_post_types(array( 'show_ui' => 1, 'exclude' => array('attachment') )); if(!empty($post_types)){ foreach($post_types as $post_type){ $list[] = $post_type . '_options'; } } // Add 'Taxonomy List' location $taxonomies = acf_get_taxonomies(); if(!empty($taxonomies)){ foreach($taxonomies as $taxonomy){ $list[] = 'tax_' . $taxonomy . '_options'; } } // Depreacted filter $list = apply_filters_deprecated('acfe/modules/multilang/options', array($list), '0.8.8.2', 'acfe/modules/multilang/exclude_options'); // Include filter $list = apply_filters('acfe/modules/multilang/include_options', $list); // Exclude filter $exclude = apply_filters('acfe/modules/multilang/exclude_options', array()); if(is_array($exclude) && !empty($exclude)){ foreach($list as $i => $option){ if(!in_array($option, $exclude)) continue; unset($list[$i]); } $list = array_values($list); } $this->options_pages = $list; } if(is_array($this->options_pages) && !empty($this->options_pages)){ return in_array($post_id, $this->options_pages); } return false; } function get_languages($pluck = '', $type = '', $plugin = ''){ // Polylang if($this->is_polylang || $plugin === 'polylang'){ return $this->polylang_get_languages($pluck, $type); // WPML }elseif($this->is_wpml || $plugin === 'wpml'){ return $this->wpml_get_languages($pluck, $type); } return array(); } function options_page_message(){ $default_language = acf_get_setting('default_language'); $current_language = acf_get_setting('current_language'); $message = false; // Polylang if($this->is_polylang){ if(!$current_language) $current_language = $default_language; $message = "Language: {$current_language}"; $nice_language = false; $nice_flag = false; $languages = pll_languages_list(array( 'hide_empty' => false, 'fields' => false )); if($languages){ foreach($languages as $language){ if($language->locale !== $current_language) continue; $nice_language = $language->name; $nice_flag = $language->flag_url; break; } } if($nice_language){ $message = " Language: {$nice_language}"; } if($default_language === $current_language){ $message .= ' (Default)'; } } // WPML elseif($this->is_wpml){ if($current_language === 'all') $current_language = 'All'; $message = "Language: {$current_language}"; if($current_language !== 'All'){ $nice_language = false; $nice_flag = false; $languages = apply_filters('wpml_active_languages', null, array('skip_missing' => 0)); if($languages){ foreach($languages as $language){ if($language['language_code'] !== $current_language) continue; $nice_language = $language['native_name']; $nice_flag = $language['country_flag_url']; break; } } if($nice_language){ $message = " Language: {$nice_language}"; } } } if(empty($message)) return; echo "
{$message}
"; } } acf_new_instance('acfe_multilang'); endif; /* * Is Multilang Enabled */ function acfe_is_multilang(){ return acf_get_instance('acfe_multilang')->is_multilang; } /* * Get Multilang Data */ function acfe_get_multilang(){ $wpml = acf_get_instance('acfe_multilang')->is_wpml; $polylang = acf_get_instance('acfe_multilang')->is_polylang; $data = array( 'dl' => acf_get_setting('default_language'), 'cl' => acf_get_setting('current_language'), 'wpml' => $wpml, 'polylang' => $polylang, ); return $data; } /* * Get Languages */ function acfe_get_multilang_languages($pluck = '', $type = '', $plugin = ''){ return acf_get_instance('acfe_multilang')->get_languages($pluck, $type, $plugin); } /* * Is Polylang */ function acfe_is_polylang(){ return acf_get_instance('acfe_multilang')->is_polylang; } /* * Is WPML */ function acfe_is_wpml(){ return acf_get_instance('acfe_multilang')->is_wpml; } /* * Get Post Language */ function acfe_get_post_lang($post_id, $field = false){ // Bail early if not multilang if(!acfe_is_multilang()) return false; // Polylang if(acfe_is_polylang()){ // Default field if(!$field) $field = 'locale'; return pll_get_post_language($post_id, $field); // WPML }elseif(acfe_is_wpml()){ $post_lang = apply_filters('wpml_post_language_details', NULL, $post_id); // Default field if(!$field) $field = 'slug'; if($field === 'locale'){ return $post_lang['locale']; }elseif($field === 'slug'){ return $post_lang['language_code']; }elseif($field === 'name'){ return $post_lang['display_name']; } return false; } return false; } /* * Get Post Translated */ function acfe_get_post_translated($post_id, $lang = false){ // Bail early if not multilang if(!acfe_is_multilang()) return $post_id; // Default $translated_post_id = $post_id; // Polylang if(acfe_is_polylang()){ $translated_post_id = pll_get_post($post_id, $lang); // WPML }elseif(acfe_is_wpml()){ $translated_post_id = apply_filters('wpml_object_id', $post_id, 'post', false, $lang); } /* if(empty($translated_post_id)) return $post_id; */ return $translated_post_id; } /* * Get Default Post Translated */ function acfe_get_post_translated_default($post_id){ // Get translated post id $translated_post_id = acfe_get_post_translated($post_id, acf_get_setting('default_language')); // Fallback to current if(empty($translated_post_id)) return $post_id; return $translated_post_id; } /* * Translate String */ function acfe_translate($string, $name = false, $textdomain = 'acfe'){ // Bail early if(!acfe_is_multilang() || empty($string)) return __($string, $textdomain); // Name compatibility if(empty($name)) $name = $string; // WPML if(acfe_is_wpml()){ // Translate (Register string during save) return apply_filters('wpml_translate_single_string', $string, $textdomain, $name); } // PolyLang if(acfe_is_polylang()){ // Register string pll_register_string($name, $string, $textdomain); // Translate return pll__($string); } // Default Translate return __($string, $textdomain); } /* * Deprecated Translate String */ function acfe__($string, $name = false, $textdomain = 'acfe'){ return acfe_translate($string, $name, $textdomain); } /* * Deprecated Translate String (echo) */ function acfe__e($string, $name = false, $textdomain = 'acfe'){ echo acfe_translate($string, $name, $textdomain); }