Skip to content

Instantly share code, notes, and snippets.

@markhowellsmead
Last active December 14, 2020 16:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markhowellsmead/7e3c298cfefc2f0572a7f2eb6afb5f43 to your computer and use it in GitHub Desktop.
Save markhowellsmead/7e3c298cfefc2f0572a7f2eb6afb5f43 to your computer and use it in GitHub Desktop.
This add-in gives you full Polylang support in WordPress customizer. By full support I mean that you customize each language site differently. Original from https://github.com/soderlind/customizer-polylang
/**
*
*/
/* global wp, jQuery */
/* exported PluginCustomizer */
var PSPolyLang = (function (api, $) {
'use strict';
var component = {
data: {
url: null,
languages: null,
current_language: null,
}
};
/**
* Initialize functionality.
*
* @param {object} args Args.
* @param {string} args.url Preview URL.
* @returns {void}
*/
component.init = function init(pll) {
_.extend(component.data, pll);
if (!pll || !pll.url || !pll.languages || !pll.current_language) {
throw new Error('Missing args');
}
api.bind('ready', function () {
api.previewer.previewUrl.set(pll.url);
var languages = pll.languages;
var current_language = pll.current_language;
var current_language_name = '';
var html = '<span style="position:relative;left:38px">Language: </span>';
html += '<select id="pll-language-select" style="position:relative; left: 35px; top: 1px; padding: 0 2em 0 .5em;">';
for (var i = 0; i < languages.length; i++) {
var language = languages[i];
var selected = (language.slug === current_language) ? 'selected' : '';
current_language_name = (language.slug === current_language) ? language.name : '';
html += '<option ' + selected + ' value="' + language.slug + '">' + language.name + '</option>';
}
html += '</select>';
$(html).prependTo('#customize-header-actions');
$('body').on('change', '#pll-language-select', function () {
var language = $(this).val();
var old_url = window.location.href;
window.location.href = updateQueryStringParameter(window.location.href, 'lang', language);
});
});
function updateQueryStringParameter(uri, key, value) {
var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
if (uri.match(re)) {
return uri.replace(re, '$1' + key + "=" + value + '$2');
} else {
return uri + separator + key + "=" + value;
}
}
};
return component;
}(wp.customize, jQuery));
<?php
/**
* This add-in gives you full Polylang support in WordPress customizer. By full support I mean that you customize each language site differently.
* Minor adaptation from https://github.com/soderlind/customizer-polylang to fit into the Hello Roots logic.
*/
namespace SayHello\Theme\Plugin;
class CustomizerPolylang
{
public function run()
{
if (!function_exists('pll_current_language') || !function_exists('pll_default_language')) {
return;
}
/**
* Force "The language is set from content" (in Language->Settings->URL modifications)
*/
$options = get_option('polylang');
if (isset($options['force_lang']) && 0 !== $options['force_lang']) {
$options['force_lang'] = 0;
update_option('polylang', $options);
}
add_filter('pll_preferred_language', '__return_false');
add_action('customize_controls_enqueue_scripts', [$this, 'addLangToCustomizerPreviewer'], 9);
add_action('wp_before_admin_bar_render', [$this, 'onWpBeforeAdminBarRender'], 100);
add_action('admin_menu', [$this, 'onAdminMenu'], 100);
$theme_stylesheet_slug = get_option('stylesheet');
$option_types = ['blogname', 'blogdescription', 'site_icon'];
add_filter('option_theme_mods_' . $theme_stylesheet_slug, [$this, 'onOptionThemeModsGet'], 10, 1);
add_filter('pre_update_option_theme_mods_' . $theme_stylesheet_slug, [$this, 'onOptionThemeModsUpdate'], 10, 2);
foreach ($option_types as $option_type) {
add_filter('pre_option_' . $option_type, [$this, 'onWpOptionGet'], 10, 3); // get_option hook.
add_filter('pre_update_option_' . $option_type, [$this, 'onWpOptionUpdate'], 10, 3); // update_option hook.
}
$this->registerPolylangColumnStrings('options_footer_columns', ['title', 'text']);
$this->registerPolylangColumnStrings('options_footer_logos', ['image', 'url']);
}
/**
* Helper to fetch custom customizer db content.
*
* @return mixed Customizer array or false.
*/
protected function getCustomCustomizerOption()
{
$current_language = pll_current_language();
$theme_slug = get_option('template');
$option_prefix = \str_replace('-', '_', $theme_slug);
$option_name = $option_prefix . '_customizer_polylang_settings_' . $current_language;
return get_option($option_name, false);
}
/**
* Helper to update custom customizer db content.
*
* @param mixed $data Data to insert.
*
* @return bool Success.
*/
protected function updateCustomCustomizerOption($data)
{
$current_language = pll_current_language();
$theme_slug = get_option('template');
$option_prefix = \str_replace('-', '_', $theme_slug);
$option_name = $option_prefix . '_customizer_polylang_settings_' . $current_language;
return update_option($option_name, $data);
}
/**
* Helper
*
* @return bool If the current language is the default language.
*/
protected function currentLangNotDefault()
{
return pll_current_language() !== pll_default_language();
}
/**
* Check the custom db field on get_option hook to be able to return custom language value.
* If the current language is default, then return from default wp option
*
* @param bool $pre_option This is false. If something else is returned wp exits the check in db and uses this value.
* @param string $option Option name asked for.
* @param mixed $default Default value, second args when asking for options.
*
* @return mixed
*/
public function onWpOptionGet($pre_option, $option, $default)
{
// If not the default language, then skip the custom check and wp will the use default options.
if ($this->currentLangNotDefault()) {
$data = $this->getCustomCustomizerOption();
// Found the custom option. Move on.
if (is_array($data) && isset($data['options']) && isset($data['options'][$option])) {
return $data['options'][$option];
}
}
return $default;
}
/**
* Update the custom db field on get_option hook.
* If the current language is not default, then return old value to prevent from saving to default wp option.
*
* @param mixed $value The new, unserialized option value.
* @param mixed $old_value The old option value.
* @param string $option Option name.
*
* @return mixed
*/
public function onWpOptionUpdate($value, $old_value, $option)
{
// Fetch custom option db field.
$data = $this->getCustomCustomizerOption();
$theme_slug = get_option('template');
// If false, the field hasn't been created yet, so it must be created.
if (false === $data) {
$data = [
'template' => $theme_slug,
'mods' => [],
'options' => [],
];
}
// Make sure the options array exists. We are going to use it soon.
if (!isset($data['options'])) {
$data['options'] = [];
}
$data['options'][$option] = $value;
// Update option value in custom db field. (Not necessary to save for default language since it uses default wp option fields for values when get option).
$this->updateCustomCustomizerOption($data);
// If the current language is not the default language, prevent saving to option table by passing the old value back. It will then exit after the filter.
if ($this->currentLangNotDefault()) {
return $old_value;
}
return $value;
}
/**
* Check the custom db field on get_option customizer field option name hook to be able to return custom language value.
* Parse arguments with default wp customizer values to make sure all are present in the return.
*
* @param array $value The customizer settings.
*
* @return array
*/
public function onOptionThemeModsGet($value)
{
$data = $this->getCustomCustomizerOption();
if (isset($data['mods']) && is_array($data['mods']) && !empty($data['mods'])) {
$value = wp_parse_args($data['mods'], $value);
}
// Remove members with integer key from mods.
foreach ($value as $key => $mod) {
if (is_numeric($key)) {
unset($value[$key]);
}
}
return $value;
}
/**
* Update custom customizer option.
* If the current language is not default, then return old value to prevent from saving to customizer wp option.
*
* @param mixed $value The new, unserialized option value.
* @param mixed $old_value The old option value.
*/
public function onOptionThemeModsUpdate($value, $old_value)
{
$current_data = $this->getCustomCustomizerOption();
$theme_slug = get_option('template');
$data = [
'template' => $theme_slug,
'mods' => isset($current_data['mods']) ? $current_data['mods'] : [],
'options' => isset($current_data['options']) ? $current_data['options'] : [],
];
if (is_array($value) && !empty($value)) {
foreach ($value as $key => $val) {
$data['mods'][$key] = $val;
}
}
$this->updateCustomCustomizerOption($data);
if ($this->currentLangNotDefault()) {
return $old_value;
}
return $value;
}
/**
* If Polylang activated, set the preview url and add select language control
*/
public function addLangToCustomizerPreviewer()
{
$handle = 'dss-add-lang-to-template';
$src = get_stylesheet_directory_uri() . '/assets/scripts/customizer-polylang.js';
$deps = ['customize-controls'];
$version = rand();
$in_footer = 1;
wp_enqueue_script($handle, $src, $deps, $version, $in_footer);
$language = (empty($_REQUEST['lang'])) ? pll_current_language() : $_REQUEST['lang'];
if (empty($language)) {
$language = pll_default_language();
}
if (!empty($_REQUEST['url'])) {
$current_url = add_query_arg('lang', $language, $_REQUEST['url']);
} else {
$current_url = add_query_arg('lang', $language, pll_home_url($language));
}
wp_add_inline_script(
$handle,
sprintf(
'PSPolyLang.init( %s );',
wp_json_encode(
[
'url' => $current_url,
'languages' => get_transient('pll_languages_list'),
'current_language' => $language,
]
)
),
'after'
);
}
/**
* Append lang="contrycode" to the customizer url in the adminbar
*
* @return void
*/
public function onWpBeforeAdminBarRender()
{
global $wp_admin_bar;
$customize_node = $wp_admin_bar->get_node('customize');
if (!empty($customize_node)) {
$customize_node->href = add_query_arg('lang', pll_current_language(), $customize_node->href);
$wp_admin_bar->add_node($customize_node);
}
}
/**
* Append lang="contrycode" to the customizer url in the Admin->Apperance->Customize menu
*
* @return void
*/
public function onAdminMenu()
{
global $submenu;
$parent = 'themes.php';
if (!isset($submenu[$parent])) {
return;
}
foreach ($submenu[$parent] as $k => $d) {
if ('customize' === $d['1']) {
$submenu[$parent][$k]['2'] = add_query_arg('lang', pll_current_language(), $submenu[$parent][$k]['2']);
break;
}
}
}
public function registerPolylangColumnStrings($option_name, $fields)
{
$columns = get_option($option_name);
$theme_name = wp_get_theme()->get('Name');
if (!empty($columns)) :
for ($i = 0; $i < $columns; $i++) :
foreach ($fields as $field) {
pll_register_string($option_name . '_' . $i . '_' . $field, get_option($option_name . '_' . $i . '_' . $field), $theme_name, true);
}
endfor;
endif;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment