Files
doitinpoland.com/wp-content/plugins/sitepress-multilingual-cms/classes/language-switcher/class-wpml-ls-settings.php
2023-09-12 21:41:04 +02:00

784 lines
22 KiB
PHP

<?php
use WPML\API\Sanitize;
use WPML\FP\Obj;
use WPML\FP\Fns;
use WPML\FP\Lst;
use WPML\FP\Maybe;
use function WPML\FP\partial;
use function WPML\FP\invoke;
class WPML_LS_Settings {
const SETTINGS_SLUG = 'wpml_language_switcher';
const DEFAULT_FLAG_WIDTH = 18;
const DEFAULT_FLAG_HEIGHT = 12;
/** @var SitePress $sitepress */
protected $sitepress;
/* @var array $settings */
private $settings;
/* @var WPML_LS_Templates $templates */
private $templates;
/* @var WPML_LS_Slot_Factory $slot_factory */
private $slot_factory;
/* @var WPML_LS_Migration $migration */
private $migration;
/* @var WPML_LS_Settings_Sanitize $sanitizer */
private $sanitizer;
/* @var WPML_LS_Settings_Strings $strings */
private $strings;
/* @var WPML_LS_Settings_Color_Presets $color_presets */
private $color_presets;
/**
* WPML_LS_Settings constructor.
*
* @param WPML_LS_Templates $templates
* @param SitePress $sitepress
* @param WPML_LS_Slot_Factory $slot_factory
* @param WPML_LS_Migration $migration
*/
public function __construct( $templates, $sitepress, $slot_factory, $migration = null ) {
$this->templates = $templates;
$this->sitepress = &$sitepress;
$this->slot_factory = $slot_factory;
$this->migration = $migration;
$this->sanitizer = new WPML_LS_Settings_Sanitize();
$this->strings = new WPML_LS_Settings_Strings( $this->slot_factory );
$this->color_presets = new WPML_LS_Settings_Color_Presets();
}
public function init_hooks() {
add_filter( 'widget_update_callback', array( $this, 'widget_update_callback_filter' ), 10, 4 );
add_action( 'update_option_sidebars_widgets', array( $this, 'update_option_sidebars_widgets_action' ), 10, 2 );
add_action( 'wpml_reset_ls_settings', array( $this, 'reset_ls_settings_action' ) );
}
/**
* @param array $ls_config
*/
public function reset_ls_settings_action( array $ls_config ) {
$restore_ls_settings = ( isset( $_GET['restore_ls_settings'] ) && 1 == $_GET['restore_ls_settings'] );
$has_valid_nonce = isset( $_GET['nonce'] )
&& wp_create_nonce( WPML_LS_Admin_UI::RESET_NONCE_NAME ) === $_GET['nonce'];
$restore_ls_settings = $restore_ls_settings && $has_valid_nonce;
if ( ! $this->sitepress->get_setting( 'language_selector_initialized' ) || $restore_ls_settings ) {
delete_option( self::SETTINGS_SLUG );
$this->settings = null;
if ( ! empty( $ls_config ) ) {
$this->sitepress->set_setting( 'language_selector_initialized', 1 );
$reset_settings = $this->read_config_settings_recursive( $ls_config['key'] );
$converted_settings = $this->migration()->get_converted_settings( $reset_settings );
if ( isset( $converted_settings['migrated'] ) && 1 === $converted_settings['migrated'] ) {
$reset_settings = $converted_settings;
} else {
$reset_settings['migrated'] = 0;
}
$this->save_settings( $reset_settings );
} else {
$this->maybe_init_settings();
}
if ( $this->sitepress->get_setting( 'setup_complete' ) && $restore_ls_settings ) {
$this->sitepress->get_wp_api()->wp_safe_redirect( $this->get_restore_redirect_url() );
}
}
}
/**
* @return string|void
*/
public function get_restore_redirect_url() {
return admin_url( 'admin.php?page=' . WPML_LS_Admin_UI::get_page_hook() . '&ls_reset=default' );
}
/**
* @param array $arr
*
* @return array
*/
public function read_config_settings_recursive( $arr ) {
$ret = array();
if ( is_array( $arr ) ) {
foreach ( $arr as $v ) {
if ( isset( $v['key'] ) && is_array( $v['key'] ) ) {
$partial = ! is_numeric( key( $v['key'] ) ) ? array( $v['key'] ) : $v['key'];
$ret[ $v['attr']['name'] ] = $this->read_config_settings_recursive( $partial );
} else {
$ret[ $v['attr']['name'] ] = $v['value'];
}
}
}
return $ret;
}
/**
* @return string
*/
public function get_settings_base_slug() {
return self::SETTINGS_SLUG;
}
/**
* @return array
*/
public function get_settings() {
$this->maybe_init_settings();
return $this->settings;
}
/**
* @return array
*/
public function get_settings_model() {
$settings = $this->get_settings();
foreach ( array( 'menus', 'sidebars', 'statics' ) as $group ) {
$slots = $this->get_setting( $group );
foreach ( $slots as $slot_slug => $slot_setting ) {
$slot_vars = $slot_setting->get_model();
$slot = new \WPML_LS_Slot( $slot_vars );
$settings[ $group ][ $slot_slug ] = $slot->get_model();
}
}
return $settings;
}
/**
* @return array
*/
private function get_default_settings() {
$core_templates = $this->get_core_templates();
$footer_slot = array(
'show' => 0,
'display_names_in_current_lang' => 1,
'template' => $core_templates['list-horizontal'],
'slot_group' => 'statics',
'slot_slug' => 'footer',
);
$post_translations = array(
'show' => 0,
'display_names_in_current_lang' => 1,
'display_before_content' => 1,
'availability_text' => esc_html__( 'This post is also available in: %s', 'sitepress' ),
'template' => $core_templates['post-translations'],
'slot_group' => 'statics',
'slot_slug' => 'post_translations',
);
$shortcode_actions = array(
'show' => 0,
'display_names_in_current_lang' => 1,
'template' => $core_templates['list-horizontal'],
'slot_group' => 'statics',
'slot_slug' => 'shortcode_actions',
);
$getMergedArgs = function ( $args ) {
$shared = [
'include_flag_width' => \WPML_LS_Settings::DEFAULT_FLAG_WIDTH,
'include_flag_height' => \WPML_LS_Settings::DEFAULT_FLAG_HEIGHT,
];
return array_merge( $shared, $args );
};
return array(
'menus' => array(),
'sidebars' => array(),
'statics' => array(
'footer' => $this->slot_factory->get_slot( $getMergedArgs( $footer_slot ) ),
'post_translations' => $this->slot_factory->get_slot( $getMergedArgs( $post_translations ) ),
'shortcode_actions' => $this->slot_factory->get_slot( $getMergedArgs( $shortcode_actions ) ),
),
'additional_css' => '',
);
}
/**
* @return array
*/
private function get_shared_settings_keys() {
return array(
// SitePress::settings => WPML_LS_Settings::settings
'languages_order' => 'languages_order',
'icl_lso_link_empty' => 'link_empty',
'icl_lang_sel_copy_parameters' => 'copy_parameters',
);
}
private function init_shared_settings() {
foreach ( $this->get_shared_settings_keys() as $sp_key => $ls_key ) {
$this->settings[ $ls_key ] = $this->sitepress->get_setting( $sp_key );
}
}
/**
* @param array<string,mixed> $new_settings
*/
private function persist_shared_settings( $new_settings ) {
foreach ( $this->get_shared_settings_keys() as $sp_key => $ls_key ) {
if ( array_key_exists( $ls_key, $new_settings ) ) {
$this->sitepress->set_setting( $sp_key, $new_settings[ $ls_key ] );
}
}
$this->sitepress->save_settings();
}
private function maybe_init_settings() {
if ( null === $this->settings ) {
$this->settings = get_option( self::SETTINGS_SLUG );
$this->handle_corrupted_settings();
if ( ! $this->settings || ! isset( $this->settings['migrated'] ) ) {
$this->settings = $this->migration()->get_converted_settings( $this->sitepress->get_settings() );
$default_settings = $this->get_default_settings();
$this->settings = wp_parse_args( $this->settings, $default_settings );
$this->save_settings( $this->settings );
}
if ( ! isset( $this->settings['converted_menu_ids'] ) ) {
$this->settings = $this->migration()->convert_menu_ids( $this->settings );
$this->persist_settings( $this->settings );
}
$this->init_shared_settings();
if ( ! $this->sitepress->get_wp_api()->is_admin() ) {
$this->settings = $this->strings->translate_all( $this->settings );
}
}
}
private function handle_corrupted_settings() {
$corrupted_settings = [];
foreach ( array( 'menus', 'sidebars', 'statics' ) as $group ) {
if ( ! isset( $this->settings[ $group ] ) ) {
continue;
}
foreach ( $this->settings[ $group ] as $key => $slot ) {
if ( $slot instanceof __PHP_Incomplete_Class ) {
unset( $this->settings[ $group ][ $key ] );
$corrupted_settings[] = ucfirst( $group ) . ' - ' . $key;
}
}
}
if ( $corrupted_settings ) {
$this->add_corrupted_settings_notice( $corrupted_settings );
}
}
/**
* @param array $corrupted_settings
*/
private function add_corrupted_settings_notice( $corrupted_settings ) {
$message = __( 'Some WPML Language Switcher settings were reinitialized because they were corrupted. Please re-configure them:', 'sitepress' );
$message .= ' ' . join( ', ', $corrupted_settings ) . '.';
$admin_notices = wpml_get_admin_notices();
$notice = $admin_notices->create_notice( 'corrupted_settings', $message, 'wpml-ls-settings' );
$notice->set_css_class_types( 'error' );
$notice->set_dismissible( true );
$notice->set_flash( true );
$admin_notices->add_notice( $notice );
}
/**
* @return array
*/
public function get_registered_sidebars() {
global $wp_registered_sidebars;
return is_array( $wp_registered_sidebars ) ? $wp_registered_sidebars : array();
}
/**
* @return array
*/
public function get_available_menus() {
$has_term_filter = remove_filter( 'get_term', array( $this->sitepress, 'get_term_adjust_id' ), 1 );
$ret = array();
$default_lang = $this->sitepress->get_default_language();
$menus = wp_get_nav_menus( array( 'orderby' => 'name' ) );
if ( $menus ) {
foreach ( $menus as $menu ) {
$menu_details = $this->sitepress->get_element_language_details( $menu->term_taxonomy_id, 'tax_nav_menu' );
if ( isset( $menu_details->language_code ) && $menu_details->language_code === $default_lang ) {
$ret[ $menu->term_id ] = $menu;
}
}
}
if ( $has_term_filter ) {
add_filter( 'get_term', array( $this->sitepress, 'get_term_adjust_id' ), 1, 1 );
}
return $ret;
}
/**
* @param array<string,mixed> $new_settings
*/
private function persist_settings( $new_settings ) {
$this->persist_shared_settings( $new_settings );
if ( null !== $new_settings && count( $new_settings ) > 0 ) {
update_option( self::SETTINGS_SLUG, $new_settings );
}
}
/**
* @param string $slot_group
* @param string $slot_slug
*
* @return WPML_LS_Slot
*/
public function get_slot( $slot_group, $slot_slug ) {
$void_settings = array( 'show' => 0 );
$groups = $this->get_settings();
$slot = isset( $groups[ $slot_group ][ $slot_slug ] )
? $groups[ $slot_group ][ $slot_slug ] : $this->slot_factory->get_slot( $void_settings );
return $slot;
}
/**
* @param int $term_id
*
* @return WPML_LS_Slot
*/
public function get_menu_settings_from_id( $term_id ) {
$menu_slot = $this->get_slot( 'menus', $term_id );
if ( $menu_slot->is_enabled() ) {
return $menu_slot;
}
if ( $term_id > 0 ) {
$menu_element = new WPML_Menu_Element( $term_id, $this->sitepress );
$default_lang = $this->sitepress->get_default_language();
$source_language_code = $menu_element->get_source_language_code();
$findSettingsInLang = function ( $lang ) use ( $menu_element ) {
return Maybe::of( $lang )
->map( [ $menu_element, 'get_translation' ] )
->map( invoke( 'get_wp_object' ) )
->reject( 'is_wp_error' )
->map( Obj::prop( 'term_id' ) )
->map( partial( [ $this, 'get_slot' ], 'menus' ) )
->filter( invoke( 'is_enabled' ) )
->getOrElse( null );
};
if ( $menu_element->get_language_code() !== $default_lang ) {
$menu_slot = $findSettingsInLang( $default_lang ) ?: $menu_slot;
}
if ( $source_language_code && $source_language_code !== $default_lang && $menu_element->get_language_code() !== $source_language_code ) {
$menu_slot = $findSettingsInLang( $source_language_code ) ?: $menu_slot;
}
}
return $menu_slot;
}
/**
* @return array
*/
public function get_active_slots() {
$ret = array();
foreach ( array( 'menus', 'sidebars', 'statics' ) as $group ) {
$slots = $this->get_setting( $group );
foreach ( $slots as $slot_slug => $slot ) {
/* @var WPML_LS_Slot $slot */
if ( $slot->is_enabled() ) {
$ret[] = $slot;
}
}
}
return $ret;
}
/**
* @return array
*/
public function get_active_templates() {
$ret = array();
$active_slots = $this->get_active_slots();
foreach ( $active_slots as $slot ) {
/* @var WPML_LS_Slot $slot */
if ( $slot->is_enabled() ) {
$ret[] = $slot->template();
}
}
return array_unique( $ret );
}
/**
* @param string $key
*
* @return mixed string|array|null
*/
public function get_setting( $key ) {
$this->maybe_init_settings();
return Obj::propOr( null, $key, $this->settings );
}
/**
* @param array $new_settings
*/
public function save_settings( $new_settings ) {
$this->maybe_init_settings();
$new_settings = $this->sanitizer->sanitize_all_settings( $new_settings );
$new_settings['menus'] = array_intersect_key( $new_settings['menus'], $this->get_available_menus() );
$new_settings['sidebars'] = array_intersect_key( $new_settings['sidebars'], $this->get_registered_sidebars() );
$new_settings = $this->convert_slot_settings_to_objects( $new_settings );
if ( $this->sitepress->is_setup_complete() ) {
$this->strings->register_all( $new_settings, $this->settings );
}
$this->synchronize_widget_instances( $new_settings['sidebars'] );
$this->persist_settings( $new_settings );
$this->settings = $new_settings;
}
/**
* @param array $settings
*
* @return array
*/
public function convert_slot_settings_to_objects( array $settings ) {
foreach ( array( 'menus', 'sidebars', 'statics' ) as $group ) {
if ( isset( $settings[ $group ] ) ) {
foreach ( $settings[ $group ] as $slot_slug => $slot_settings ) {
if ( is_array( $slot_settings ) ) {
$slot_settings['slot_slug'] = $slot_slug;
$slot_settings['slot_group'] = $group;
}
$settings[ $group ][ $slot_slug ] = $this->slot_factory->get_slot( $slot_settings );
}
}
}
return $settings;
}
/**
* @param array<string,\WPML_LS_Slot> $sidebar_slots
*/
private function synchronize_widget_instances( $sidebar_slots ) {
require_once ABSPATH . '/wp-admin/includes/widgets.php';
$wpml_ls_widget = new WPML_LS_Widget();
$sidebars_widgets = $this->get_refreshed_sidebars_widgets();
if ( is_array( $sidebars_widgets ) ) {
foreach ( $sidebars_widgets as $sidebar => $widgets ) {
if ( 'wp_inactive_widgets' === $sidebar ) {
continue;
}
$found = false;
if ( is_array( $widgets ) ) {
foreach ( $widgets as $key => $widget_id ) {
if ( strpos( $widget_id, WPML_LS_Widget::SLUG ) === 0 ) {
if ( $found ) { // Only synchronize the first LS widget instance per sidebar
unset( $sidebars_widgets[ $sidebar ][ $key ] );
continue;
}
$found = true;
if ( ! isset( $sidebar_slots[ $sidebar ] ) ) {
$wpml_ls_widget->delete_instance( $widget_id );
unset( $sidebars_widgets[ $sidebar ][ $key ] );
} else {
$wpml_ls_widget->update_instance( $sidebar_slots[ $sidebar ], $widget_id );
}
}
}
}
if ( ! $found ) {
if ( isset( $sidebar_slots[ $sidebar ] ) ) {
$new_instance_id = $wpml_ls_widget->create_new_instance( $sidebar_slots[ $sidebar ] );
$sidebars_widgets[ $sidebar ] = is_array( $sidebars_widgets[ $sidebar ] ) ? $sidebars_widgets[ $sidebar ] : array();
array_unshift( $sidebars_widgets[ $sidebar ], $new_instance_id );
}
}
}
}
$is_hooked = has_action( 'update_option_sidebars_widgets', array( $this, 'update_option_sidebars_widgets_action' ) );
if ( $is_hooked ) {
remove_action( 'update_option_sidebars_widgets', array( $this, 'update_option_sidebars_widgets_action' ), 10 );
}
wp_set_sidebars_widgets( $sidebars_widgets );
if ( $is_hooked ) {
add_action( 'update_option_sidebars_widgets', array( $this, 'update_option_sidebars_widgets_action' ), 10, 2 );
}
}
/** @return array */
private function get_refreshed_sidebars_widgets() {
global $_wp_sidebars_widgets;
// Clear cached value used in wp_get_sidebars_widgets().
$_wp_sidebars_widgets = null;
return wp_get_sidebars_widgets();
}
/**
* @param array $old_sidebars
* @param array $sidebars
*/
public function update_option_sidebars_widgets_action( $old_sidebars, $sidebars ) {
unset( $sidebars['wp_inactive_widgets'], $sidebars['array_version'] );
$this->maybe_init_settings();
if ( is_array( $sidebars ) ) {
foreach ( $sidebars as $sidebar_slug => $widgets ) {
$this->synchronize_sidebar_settings( $sidebar_slug, $widgets );
}
}
$this->save_settings( $this->settings );
}
/**
* @param string $sidebar_slug
* @param array $widgets
*/
private function synchronize_sidebar_settings( $sidebar_slug, $widgets ) {
$this->settings['sidebars'][ $sidebar_slug ] = isset( $this->settings['sidebars'][ $sidebar_slug ] )
? $this->settings['sidebars'][ $sidebar_slug ] : array();
$widget_id = $this->find_first_ls_widget( $widgets );
if ( $widget_id === false ) {
unset( $this->settings['sidebars'][ $sidebar_slug ] );
} else {
$instance_number = str_replace( WPML_LS_Widget::SLUG . '-', '', $widget_id );
$widget_class_options = get_option( 'widget_' . WPML_LS_Widget::SLUG );
$widget_instance_options = isset( $widget_class_options[ $instance_number ] )
? $widget_class_options[ $instance_number ] : array();
$this->settings['sidebars'][ $sidebar_slug ] = $this->get_slot_from_widget_instance( $widget_instance_options );
}
}
/**
* @param array $instance
* @param array $new_instance
* @param array|null $old_instance
* @param WP_Widget $widget
*
* @return array
*/
public function widget_update_callback_filter( array $instance, array $new_instance, $old_instance, WP_Widget $widget ) {
if ( strpos( $widget->id_base, WPML_LS_Widget::SLUG ) === 0 ) {
$sidebar_id = Sanitize::stringProp( 'sidebar', $_POST );
$sidebar_id = $sidebar_id ? $sidebar_id : $this->find_parent_sidebar( $widget->id );
if ( $sidebar_id ) {
$this->maybe_init_settings();
if ( isset( $this->settings['sidebars'][ $sidebar_id ] ) ) {
$this->settings['sidebars'][ $sidebar_id ] = $this->get_slot_from_widget_instance( $instance );
}
$this->save_settings( $this->settings );
}
}
return $instance;
}
/**
* @param array $widget_instance
*
* @return WPML_LS_Slot
*/
private function get_slot_from_widget_instance( $widget_instance ) {
$slot = isset( $widget_instance['slot'] ) ? $widget_instance['slot'] : array();
if ( ! is_a( $slot, 'WPML_LS_Sidebar_Slot' ) ) {
$slot = $this->slot_factory->get_default_slot_arguments( 'sidebars' );
$slot = $this->slot_factory->get_slot( $slot );
}
return $slot;
}
/**
* Find in which sidebar a language switcher instance is set
*
* @param string $widget_to_find
*
* @return bool|string
*/
private function find_parent_sidebar( $widget_to_find ) {
$sidebars_widgets = wp_get_sidebars_widgets();
if ( is_array( $sidebars_widgets ) ) {
foreach ( $sidebars_widgets as $sidebar_id => $widgets ) {
if ( is_array( $widgets ) ) {
foreach ( $widgets as $widget ) {
if ( $widget_to_find === $widget ) {
return $sidebar_id;
}
}
}
}
}
return false;
}
/**
* Find the first language switcher in an array of widgets
*
* @param array $widgets
*
* @return string
*/
private function find_first_ls_widget( $widgets ) {
$ret = false;
$widgets = is_array( $widgets ) ? $widgets : array();
foreach ( $widgets as $widget_id ) {
if ( strpos( $widget_id, WPML_LS_Widget::SLUG ) === 0 ) {
$ret = $widget_id;
break;
}
}
return $ret;
}
/**
* @return array
*/
public function get_ordered_languages() {
$active_languages = $this->sitepress->get_active_languages();
foreach ( $active_languages as $code => $language ) {
$active_languages[ $code ]['flag_img'] = $this->sitepress->get_flag_image( $code );
}
return $this->sitepress->order_languages( $active_languages );
}
/**
* @return array
*/
public function get_default_color_schemes() {
return $this->color_presets->get_defaults();
}
/**
* @param mixed|null|string $slug
*
* @return mixed|array|string
*/
public function get_core_templates( $slug = null ) {
$parameters = WPML_Language_Switcher::parameters();
$core_templates = isset( $parameters['core_templates'] ) ? $parameters['core_templates'] : array();
$return = $core_templates;
if ( ! empty( $slug ) ) {
$return = isset( $return[ $slug ] ) ? $return[ $slug ] : null;
}
return $return;
}
/**
* @param string|null $template_slug
*
* @return bool
*/
public function can_load_styles( $template_slug = null ) {
if ( $template_slug ) {
$template = $this->templates->get_template( $template_slug );
$can_load = ! ( $template->is_core() && $this->sitepress->get_wp_api()->constant( 'ICL_DONT_LOAD_LANGUAGE_SELECTOR_CSS' ) );
} else {
$can_load = ! $this->sitepress->get_wp_api()->constant( 'ICL_DONT_LOAD_LANGUAGE_SELECTOR_CSS' );
}
return $can_load;
}
/**
* @param string|null $template_slug
*
* @return bool
*/
public function can_load_script( $template_slug = null ) {
if ( $template_slug ) {
$template = $this->templates->get_template( $template_slug );
$can_load = ! ( $template->is_core() && $this->sitepress->get_wp_api()->constant( 'ICL_DONT_LOAD_LANGUAGES_JS' ) );
} else {
$can_load = ! $this->sitepress->get_wp_api()->constant( 'ICL_DONT_LOAD_LANGUAGES_JS' );
}
return $can_load;
}
/**
* @return WPML_LS_Migration
*/
private function migration() {
if ( ! $this->migration ) {
$this->migration = new WPML_LS_Migration( $this, $this->sitepress, $this->slot_factory );
}
return $this->migration;
}
}