web/wp-content/plugins/acf-extended/includes/multilang.php (407 lines of code) (raw):
<?php
if(!defined('ABSPATH')){
exit;
}
if(!class_exists('acfe_multilang')):
class acfe_multilang{
// vars
var $is_wpml = false;
var $is_polylang = false;
var $is_multilang = false;
var $options_pages = array();
/**
* construct
*/
function __construct(){
// wpml
if(defined('ICL_SITEPRESS_VERSION')){
$this->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);
}
}
/**
* init
*/
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);
}
/**
* polylang_preload_reference
*
* @param $null
* @param $field_name
* @param $post_id
*
* @return mixed|null
*/
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);
}
/**
* polylang_preload_value
*
* @param $null
* @param $post_id
* @param $field
*
* @return mixed
*/
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);
}
/**
* polylang_validate_preload_post_id
*
* @param $post_id
*
* @return array|false|string|string[]|null
*/
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_get_languages
*
* https://wpml.org/documentation/support/wpml-coding-api/wpml-hooks-reference/
*
* @param $pluck
* @param $type
*
* @return array|int[]|mixed|string[]|null
*/
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_get_languages
*
* 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/
*
* @param $pluck
* @param $type
*
* @return array|string[]
*/
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;
}
/**
* set_options_post_id
*
* @param $post_id
* @param $original_post_id
*
* @return mixed|string
*/
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;
}
/**
* is_localized
*
* @param $post_id
*
* @return bool
*/
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<locale>[_\-][A-Za-z]{2}_[A-Za-z]{2})$|(?P<code>[_\-][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);
}
/**
* is_options_page
*
* @param $post_id
*
* @return bool
*/
function is_options_page($post_id){
// check if post id already in options pages
if(in_array($post_id, $this->options_pages)){
return true;
}
// get acf options pages
$options_pages = acf_get_array(acf_get_options_pages());
$list = wp_list_pluck($options_pages, 'post_id', true);
// add 'post type list' location
$post_types = acf_get_post_types(array(
'show_ui' => 1,
'exclude' => array('attachment')
));
foreach($post_types as $post_type){
$list[] = "{$post_type}_options";
}
// add 'taxonomy list' location
$taxonomies = acf_get_taxonomies();
foreach($taxonomies as $taxonomy){
$list[] = "tax_{$taxonomy}_options";
}
// deprecated 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)){
unset($list[ $i ]);
}
}
$list = array_values($list);
}
$this->options_pages = $list;
return in_array($post_id, $this->options_pages);
}
/**
* get_languages
*
* @param $pluck
* @param $type
* @param $plugin
*
* @return array|int[]|mixed|string[]|null
*/
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();
}
/**
* options_page_message
*/
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 = "<img src='{$nice_flag}' style='margin-right:5px;vertical-align:-1px;' /> 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 = "<img src='{$nice_flag}' style='margin-right:5px;vertical-align:-1px; width:16px; height:11px;' /> Language: {$nice_language}";
}
}
}
if(empty($message)){
return;
}
echo "<div class='misc-pub-section' style='padding-top:15px; padding-bottom:15px;'>{$message}</div>";
}
}
acf_new_instance('acfe_multilang');
endif;
/**
* acfe_is_multilang
*
* @return mixed
*/
function acfe_is_multilang(){
return acf_get_instance('acfe_multilang')->is_multilang;
}
/**
* acfe_get_multilang
*
* @return array
*/
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;
}
/**
* acfe_get_multilang_languages
*
* @param $pluck
* @param $type
* @param $plugin
*
* @return mixed
*/
function acfe_get_multilang_languages($pluck = '', $type = '', $plugin = ''){
return acf_get_instance('acfe_multilang')->get_languages($pluck, $type, $plugin);
}
/**
* acfe_is_polylang
*
* @return mixed
*/
function acfe_is_polylang(){
return acf_get_instance('acfe_multilang')->is_polylang;
}
/**
* acfe_is_wpml
*
* @return mixed
*/
function acfe_is_wpml(){
return acf_get_instance('acfe_multilang')->is_wpml;
}
/**
* acfe_get_post_lang
*
* @param $post_id
* @param $field
*
* @return false|mixed|string
*/
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;
}
/**
* acfe_get_post_translated
*
* @param $post_id
* @param $lang
*
* @return false|int|mixed|null
*/
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;
}
/**
* acfe_get_post_translated_default
*
* @param $post_id
*
* @return int|mixed
*/
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;
}
/**
* acfe_translate
*
* @param $string
* @param $name
* @param $textdomain
*
* @return mixed|string|null
*/
function acfe_translate($string, $name = '', $textdomain = ''){
// no polylang/wpml
if(!acfe_is_multilang()){
return acf_translate($string);
}
// acf translate
if(empty($name) && empty($textdomain)){
return acf_translate($string);
}
// is array
if(is_array($string)){
foreach($string as $k => $v){
$name = !is_numeric($k) ? ucfirst($k) : $name;
$string[ $k ] = acfe_translate($v, $name, $textdomain);
}
}
// bail early if not string
if(!is_string($string)){
return $string;
}
// bail early if empty
if($string === ''){
return $string;
}
// wpml
if(acfe_is_wpml()){
return apply_filters('wpml_translate_single_string', $string, $textdomain, $name);
}
// polylang
if(acfe_is_polylang()){
pll_register_string($name, $string, $textdomain);
return pll__($string);
}
// default translate
return acf_translate($string);
}
/**
* acfe_register_translate
*
* @param $string
* @param $name
* @param $textdomain
*/
function acfe_register_translate($string, $name = '', $textdomain = ''){
// wpml only
if(acfe_is_wpml()){
// is array
if(is_array($string)){
foreach($string as $k => $v){
$name = !is_numeric($k) ? ucfirst($k) : $name;
acfe_register_translate($v, $name, $textdomain);
}
// string
}else{
do_action('wpml_register_single_string', $textdomain, $name, $string);
}
}
}
/**
* acfe__
*
* @param $string
* @param $name
* @param $textdomain
*
* @deprecated
*
* @return mixed|string|null
*/
function acfe__($string, $name = false, $textdomain = 'acfe'){
return acfe_translate($string, $name, $textdomain);
}
/**
* acfe__e
*
* @param $string
* @param $name
* @param $textdomain
*
* @deprecated
*/
function acfe__e($string, $name = false, $textdomain = 'acfe'){
echo acfe_translate($string, $name, $textdomain);
}