Commit fe7259dc authored by Simon's avatar Simon

release 1.15.1

parent 00bf66dc
...@@ -20,9 +20,9 @@ ...@@ -20,9 +20,9 @@
## Production ## Production
- build CSS & JS assets - `C:\web\dev.biuro\ npm run build` - build CSS & JS assets - `C:\web\dev.biuro\ npm run build`
- build new image `docker build -t biuro/web:1.15.0 .` (update version number) - build new image `docker build -t biuro/web:1.15.1 .` (update version number)
- login to biuro docker account `docker login --username=biuro --password=9Ndtjd2vKsLvGuFOeFq1KdJs` - login to biuro docker account `docker login --username=biuro --password=9Ndtjd2vKsLvGuFOeFq1KdJs`
- push image to docker repository - `docker push biuro/web:1.15.0` - push image to docker repository - `docker push biuro/web:1.15.1`
## Production ## Production
- update biuro/web image version in .env file (staging or www) - update biuro/web image version in .env file (staging or www)
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
interface LocoArrayInterface extends ArrayAccess, Iterator, Countable, JsonSerializable { public function getArrayCopy(); } interface LocoArrayInterface extends ArrayAccess, Iterator, Countable, JsonSerializable { public function getArrayCopy(); }
class LocoHeaders extends ArrayIterator implements LocoArrayInterface { private $map = array(); public function __construct(array $raw = array() ){ if( $raw ){ $keys = array_keys( $raw ); $this->map = array_combine( array_map( 'strtolower', $keys ), $keys ); parent::__construct($raw); } } public function normalize( $key ){ $k = strtolower($key); return isset($this->map[$k]) ? $this->map[$k] : null; } public function add($key, $val ){ $this->offsetSet( $key, $val ); return $this; } public function __toString(){ $pairs = array(); foreach( $this as $key => $val ){ $pairs[] = $key.': '.$val; } return implode("\n", $pairs ); } public function trimmed($prop ){ return trim( $this->__get($prop) ); } public function has($key ){ $k = strtolower($key); return isset($this->map[$k]); } public function __get($key ){ return $this->offsetGet( $key ); } public function __set($key, $val ){ $this->offsetSet( $key, $val ); } public function offsetExists($k ){ return ! is_null( $this->normalize($k) ); } public function offsetGet($k ){ $k = $this->normalize($k); if( is_null($k) ){ return ''; } return parent::offsetGet($k); } public function offsetSet($key, $v ){ $k = strtolower($key); if( isset($this->map[$k]) && $key !== $this->map[$k] ){ parent::offsetUnset( $this->map[$k] ); } $this->map[$k] = $key; parent::offsetSet( $key, $v ); } public function offsetUnset($key ){ $k = strtolower($key); if( isset($this->map[$k]) ){ parent::offsetUnset( $this->map[$k] ); unset( $this->map[$k] ); } } public function jsonSerialize(){ return $this->getArrayCopy(); } public function keys(){ trigger_error('Is this required?', E_USER_NOTICE); return array_values( $this->map ); } } class LocoHeaders extends ArrayIterator implements LocoArrayInterface { private $map = array(); public function __construct(array $raw = array() ){ if( $raw ){ $keys = array_keys( $raw ); $this->map = array_combine( array_map( 'strtolower', $keys ), $keys ); parent::__construct($raw); } } public function normalize( $key ){ $k = strtolower($key); return isset($this->map[$k]) ? $this->map[$k] : null; } public function add($key, $val ){ $this->offsetSet( $key, $val ); return $this; } public function __toString(){ $pairs = array(); foreach( $this as $key => $val ){ $pairs[] = $key.': '.$val; } return implode("\n", $pairs ); } public function trimmed($prop ){ return trim( $this->__get($prop) ); } public function has($key ){ $k = strtolower($key); return isset($this->map[$k]); } public function __get($key ){ return $this->offsetGet( $key ); } public function __set($key, $val ){ $this->offsetSet( $key, $val ); } public function offsetExists($k ){ return ! is_null( $this->normalize($k) ); } public function offsetGet($k ){ $k = $this->normalize($k); if( is_null($k) ){ return ''; } return parent::offsetGet($k); } public function offsetSet($key, $v ){ $k = strtolower($key); if( isset($this->map[$k]) && $key !== $this->map[$k] ){ parent::offsetUnset( $this->map[$k] ); } $this->map[$k] = $key; parent::offsetSet( $key, $v ); } public function offsetUnset($key ){ $k = strtolower($key); if( isset($this->map[$k]) ){ parent::offsetUnset( $this->map[$k] ); unset( $this->map[$k] ); } } public function jsonSerialize(){ return $this->getArrayCopy(); } public function keys(){ trigger_error('Is this required?', E_USER_NOTICE); return array_values( $this->map ); } }
function loco_normalize_charset( $cs ){ if( preg_match('/^UTF-?8$/i',$cs) ){ return 'UTF-8'; } $aliases = @mb_encoding_aliases($cs); if( false === $aliases ){ throw new InvalidArgumentException('Unsupported character encoding: '.$cs ); } if( $r = preg_grep('/^ISO[-_]\\d+[-_]\\d+$/i',$aliases) ){ $cs = current($aliases); $cs = strtr( strtoupper($cs), '_', '-' ); } else if( in_array('US-ASCII',$aliases,true) ){ $cs = 'US-ASCII'; } return $cs; } function loco_normalize_charset( $cs ){ if( preg_match('/^UTF-?8$/i',$cs) ){ return 'UTF-8'; } $aliases = @mb_encoding_aliases($cs); if( false === $aliases ){ throw new InvalidArgumentException('Unsupported character encoding: '.$cs ); } if( $r = preg_grep('/^ISO[-_]\\d+[-_]\\d+$/i',$aliases) ){ $cs = current($aliases); $cs = strtr( strtoupper($cs), '_', '-' ); } else if( in_array('US-ASCII',$aliases,true) ){ $cs = 'US-ASCII'; } return $cs; }
class LocoPoHeaders extends LocoHeaders { private $cs; public function getCharset(){ $cs = $this->cs; if( is_null($cs) ){ $cs = ''; $raw = $this->offsetGet('content-type'); if( $raw && preg_match('!\\bcharset[= ]+([-\\w]+)!',$raw,$r) ){ try { $cs = loco_normalize_charset($r[1]); } catch( Loco_error_ParseException $e ){ $cs = null; } catch( Throwable $e ){ trigger_error($e->getMessage(),E_USER_NOTICE); $cs = null; } } $this->cs = $cs; } return $cs; } public function setCharset( $to ){ $to = loco_normalize_charset($to); $from = $this->getCharset(); $this->cs = $to; $this['Content-Type'] = 'text/plain; charset='.$to; if( $from && $from !== $to ){ foreach( $this as $key => $val ){ $this[$key] = mb_convert_encoding($val,$to,$from); } } return $to; } public static function fromMsgstr( $str ){ $headers = new LocoPoHeaders; $key = ''; foreach( preg_split('/[\\r\\n]+/',$str) as $line ){ $i = strpos($line,':'); if( is_int($i) ){ $key = trim( substr($line,0,$i), " \t" ); $headers->offsetSet( $key, ltrim( substr($line,++$i)," \t" ) ); } else if( '' !== $key ){ $headers->offsetSet( $key, $headers->offsetGet($key)."\n".$line ); } } $cs = $headers->getCharset(); if( $cs && 'UTF-8' !== $cs && 'UTF-8' !== mb_detect_encoding($str,array('UTF-8',$cs),true) ){ foreach( $headers as $key => $val ){ $headers[$key] = mb_convert_encoding($val,'UTF-8',array($cs)); } } return $headers; } public static function fromSource( $raw ){ $po = new LocoPoParser($raw); $po->parse(0); return $po->getHeader(); } } class LocoPoHeaders extends LocoHeaders { private $cs; public function getCharset(){ $cs = $this->cs; if( is_null($cs) ){ $cs = ''; $raw = $this->offsetGet('content-type'); if( $raw && preg_match('!\\bcharset[= ]+([-\\w]+)!',$raw,$r) ){ try { $cs = loco_normalize_charset($r[1]); } catch( InvalidArgumentException $e ){ $cs = null; } catch( Throwable $e ){ trigger_error( $e->getMessage(), E_USER_NOTICE ); $cs = null; } } $this->cs = $cs; } return $cs; } public function setCharset( $to ){ $to = loco_normalize_charset($to); $from = $this->getCharset(); $this->cs = $to; $this['Content-Type'] = 'text/plain; charset='.$to; if( $from && $from !== $to ){ foreach( $this as $key => $val ){ $this[$key] = mb_convert_encoding($val,$to,$from); } } return $to; } public static function fromMsgstr( $str ){ $headers = new LocoPoHeaders; $key = ''; foreach( preg_split('/[\\r\\n]+/',$str) as $line ){ $i = strpos($line,':'); if( is_int($i) ){ $key = trim( substr($line,0,$i), " \t" ); $headers->offsetSet( $key, ltrim( substr($line,++$i)," \t" ) ); } else if( '' !== $key ){ $headers->offsetSet( $key, $headers->offsetGet($key)."\n".$line ); } } $cs = $headers->getCharset(); if( $cs && 'UTF-8' !== $cs && 'UTF-8' !== mb_detect_encoding($str,array('UTF-8',$cs),true) ){ foreach( $headers as $key => $val ){ $headers[$key] = mb_convert_encoding($val,'UTF-8',array($cs)); } } return $headers; } public static function fromSource( $raw ){ $po = new LocoPoParser($raw); $po->parse(0); return $po->getHeader(); } }
function loco_convert_utf8( $str, $enc ){ if( '' === $enc ){ if( false === preg_match('//u',$str) ){ $str = mb_convert_encoding( $str, 'UTF-8', 'cp1252' ); } } else if( 'UTF-8' === $enc || 'US-ASCII' === $enc ){ if( false === preg_match('//u',$str) ){ throw new Loco_error_ParseException('Bad '.$enc.' encoding'); } } else if( 'ISO-8859-1' === $enc ) { $str = mb_convert_encoding( $str, 'UTF-8', 'cp1252' ); } else { $str = mb_convert_encoding( $str, 'UTF-8', $enc ); } return $str; } function loco_convert_utf8( $str, $enc ){ if( '' === $enc ){ if( false === preg_match('//u',$str) ){ $str = mb_convert_encoding( $str, 'UTF-8', 'cp1252' ); } } else if( 'UTF-8' === $enc || 'US-ASCII' === $enc ){ if( false === preg_match('//u',$str) ){ throw new Loco_error_ParseException('Bad '.$enc.' encoding'); } } else if( 'ISO-8859-1' === $enc ) { $str = mb_convert_encoding( $str, 'UTF-8', 'cp1252' ); } else { $str = mb_convert_encoding( $str, 'UTF-8', $enc ); } return $str; }
abstract class LocoGettextParser { private $head; private $cs; abstract public function parse( $limit = -1 ); protected function setHeader( LocoPoHeaders $head ){ $this->head = $head; if( $cs = $head->getCharset() ){ if( is_null($this->cs) ){ $this->setCharset($cs); } } return $head; } public function getHeader(){ return $this->head; } protected function setCharset( $cs ){ $this->cs = $cs; } protected function getCharset(){ return $this->cs; } protected function str( $str ){ if( '' !== $str ){ $enc = (string) $this->cs; $str = loco_convert_utf8( $str, $enc ); } return $str; } } abstract class LocoGettextParser { private $head; private $cs; abstract public function parse( $limit = -1 ); protected function setHeader( LocoPoHeaders $head ){ $this->head = $head; if( $cs = $head->getCharset() ){ if( is_null($this->cs) ){ $this->setCharset($cs); } } return $head; } public function getHeader(){ return $this->head; } protected function setCharset( $cs ){ $this->cs = $cs; } protected function getCharset(){ return $this->cs; } protected function str( $str ){ if( '' !== $str ){ $enc = (string) $this->cs; $str = loco_convert_utf8( $str, $enc ); } return $str; } }
function loco_remove_bom( $s, &$c ){ $bom = substr($s,0,2); if( "\xFF\xFE" === $bom ){ $c = 'UTF-16LE'; return substr($s,2); } if( "\xFE\xFF" === $bom ){ $c = 'UTF-16BE'; return substr($s,2); } if( "\xEF\xBB" === $bom && "\xBF" === $s[2] ){ $c = 'UTF-8'; return substr($s,3); } $c = ''; return $s; } function loco_remove_bom( $s, &$c ){ $bom = substr($s,0,2); if( "\xFF\xFE" === $bom ){ $c = 'UTF-16LE'; return substr($s,2); } if( "\xFE\xFF" === $bom ){ $c = 'UTF-16BE'; return substr($s,2); } if( "\xEF\xBB" === $bom && "\xBF" === $s[2] ){ $c = 'UTF-8'; return substr($s,3); } $c = ''; return $s; }
......
...@@ -4,7 +4,7 @@ Plugin Name: Loco Translate ...@@ -4,7 +4,7 @@ Plugin Name: Loco Translate
Plugin URI: https://wordpress.org/plugins/loco-translate/ Plugin URI: https://wordpress.org/plugins/loco-translate/
Description: Translate themes and plugins directly in WordPress Description: Translate themes and plugins directly in WordPress
Author: Tim Whitlock Author: Tim Whitlock
Version: 2.3.2 Version: 2.3.3
Author URI: https://localise.biz/wordpress/plugin Author URI: https://localise.biz/wordpress/plugin
Text Domain: loco-translate Text Domain: loco-translate
Domain Path: /languages/ Domain Path: /languages/
...@@ -36,7 +36,7 @@ function loco_plugin_file(){ ...@@ -36,7 +36,7 @@ function loco_plugin_file(){
* @return string * @return string
*/ */
function loco_plugin_version(){ function loco_plugin_version(){
return '2.3.2'; return '2.3.3';
} }
......
...@@ -4,7 +4,7 @@ Tags: translation, translators, localization, localisation, l10n, i18n, Gettext, ...@@ -4,7 +4,7 @@ Tags: translation, translators, localization, localisation, l10n, i18n, Gettext,
Requires at least: 4.1 Requires at least: 4.1
Requires PHP: 5.2.4 Requires PHP: 5.2.4
Tested up to: 5.4 Tested up to: 5.4
Stable tag: 2.3.2 Stable tag: 2.3.3
License: GPLv2 or later License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html License URI: http://www.gnu.org/licenses/gpl-2.0.html
...@@ -97,6 +97,9 @@ We don't collect your data or snoop on you. See the [plugin privacy notice](http ...@@ -97,6 +97,9 @@ We don't collect your data or snoop on you. See the [plugin privacy notice](http
== Changelog == == Changelog ==
= 2.3.3 =
* Fixed fatal error when class not found
= 2.3.2 = = 2.3.2 =
* Removed login/email from default Last-Translator credit * Removed login/email from default Last-Translator credit
* Bumped WP compatibility to 5.4 * Bumped WP compatibility to 5.4
...@@ -319,7 +322,7 @@ We don't collect your data or snoop on you. See the [plugin privacy notice](http ...@@ -319,7 +322,7 @@ We don't collect your data or snoop on you. See the [plugin privacy notice](http
== Upgrade Notice == == Upgrade Notice ==
= 2.3.2 = = 2.3.3 =
* Various bug fixes and improvements * Various bug fixes and improvements
......
...@@ -48,18 +48,27 @@ class PLL_Admin_Base extends PLL_Base { ...@@ -48,18 +48,27 @@ class PLL_Admin_Base extends PLL_Base {
public function init() { public function init() {
parent::init(); parent::init();
$this->notices = new PLL_Admin_Notices( $this );
if ( Polylang::is_wizard() && class_exists( 'PLL_Wizard_Pro' ) ) {
// Instantiate PLL_Wizard_Pro class after all PLL_Admin object is all initialized.
// After PLL_Admin::maybe_load_sync_post which is hooked on admin_init with priority 20.
add_action( 'admin_init', array( $this, 'instantiate_wizard_pro' ), 30 );
}
$this->wizard = new PLL_Wizard( $this );
if ( ! $this->model->get_languages_list() ) { if ( ! $this->model->get_languages_list() ) {
return; return;
} }
$this->notices = new PLL_Admin_Notices( $this );
$this->links = new PLL_Admin_Links( $this ); // FIXME needed here ? $this->links = new PLL_Admin_Links( $this ); // FIXME needed here ?
$this->static_pages = new PLL_Admin_Static_Pages( $this ); // FIXME needed here ? $this->static_pages = new PLL_Admin_Static_Pages( $this ); // FIXME needed here ?
$this->filters_links = new PLL_Filters_Links( $this ); // FIXME needed here ? $this->filters_links = new PLL_Filters_Links( $this ); // FIXME needed here ?
// Filter admin language for users // Filter admin language for users
// We must not call user info before WordPress defines user roles in wp-settings.php // We must not call user info before WordPress defines user roles in wp-settings.php
add_filter( 'setup_theme', array( $this, 'init_user' ) ); add_action( 'setup_theme', array( $this, 'init_user' ) );
add_filter( 'request', array( $this, 'request' ) ); add_filter( 'request', array( $this, 'request' ) );
// Adds the languages in admin bar // Adds the languages in admin bar
...@@ -78,6 +87,8 @@ class PLL_Admin_Base extends PLL_Base { ...@@ -78,6 +87,8 @@ class PLL_Admin_Base extends PLL_Base {
* @since 0.1 * @since 0.1
*/ */
public function add_menus() { public function add_menus() {
global $admin_page_hooks;
// Prepare the list of tabs // Prepare the list of tabs
$tabs = array( 'lang' => __( 'Languages', 'polylang' ) ); $tabs = array( 'lang' => __( 'Languages', 'polylang' ) );
...@@ -97,11 +108,14 @@ class PLL_Admin_Base extends PLL_Base { ...@@ -97,11 +108,14 @@ class PLL_Admin_Base extends PLL_Base {
*/ */
$tabs = apply_filters( 'pll_settings_tabs', $tabs ); $tabs = apply_filters( 'pll_settings_tabs', $tabs );
$parent = '';
foreach ( $tabs as $tab => $title ) { foreach ( $tabs as $tab => $title ) {
$page = 'lang' === $tab ? 'mlang' : "mlang_$tab"; $page = 'lang' === $tab ? 'mlang' : "mlang_$tab";
if ( empty( $parent ) ) { if ( empty( $parent ) ) {
$parent = $page; $parent = $page;
add_menu_page( $title, __( 'Languages', 'polylang' ), 'manage_options', $page, null, 'dashicons-translation' ); add_menu_page( $title, __( 'Languages', 'polylang' ), 'manage_options', $page, null, 'dashicons-translation' );
$admin_page_hooks[ $page ] = 'languages'; // Hack to avoid the localization of the hook name. See: https://core.trac.wordpress.org/ticket/18857
} }
add_submenu_page( $parent, $title, $title, 'manage_options', $page, array( $this, 'languages_page' ) ); add_submenu_page( $parent, $title, $title, 'manage_options', $page, array( $this, 'languages_page' ) );
...@@ -421,4 +435,12 @@ class PLL_Admin_Base extends PLL_Base { ...@@ -421,4 +435,12 @@ class PLL_Admin_Base extends PLL_Base {
); );
} }
} }
/**
* Instantiate PLL_Wizard_Pro class.
*
* @since 2.7
*/
public function instantiate_wizard_pro() {
$this->wizard_pro = new PLL_Wizard_Pro( $this );
}
} }
...@@ -66,10 +66,10 @@ class PLL_Admin_Classic_Editor { ...@@ -66,10 +66,10 @@ class PLL_Admin_Classic_Editor {
*/ */
public function post_language() { public function post_language() {
global $post_ID; global $post_ID;
$post_id = $post_ID;
$post_type = get_post_type( $post_ID ); $post_type = get_post_type( $post_ID );
$from_post_id = isset( $_GET['from_post'] ) ? (int) $_GET['from_post'] : 0; // phpcs:ignore WordPress.Security.NonceVerification // phpcs:ignore WordPress.Security.NonceVerification, WordPressVIPMinimum.Variables.VariableAnalysis.UnusedVariable
$from_post_id = isset( $_GET['from_post'] ) ? (int) $_GET['from_post'] : 0;
$lang = ( $lg = $this->model->post->get_language( $post_ID ) ) ? $lg : $lang = ( $lg = $this->model->post->get_language( $post_ID ) ) ? $lg :
( isset( $_GET['new_lang'] ) ? $this->model->get_language( sanitize_key( $_GET['new_lang'] ) ) : // phpcs:ignore WordPress.Security.NonceVerification ( isset( $_GET['new_lang'] ) ? $this->model->get_language( sanitize_key( $_GET['new_lang'] ) ) : // phpcs:ignore WordPress.Security.NonceVerification
...@@ -130,9 +130,8 @@ class PLL_Admin_Classic_Editor { ...@@ -130,9 +130,8 @@ class PLL_Admin_Classic_Editor {
} }
global $post_ID; // Obliged to use the global variable for wp_popular_terms_checklist global $post_ID; // Obliged to use the global variable for wp_popular_terms_checklist
$post_id = $post_ID = (int) $_POST['post_id']; $post_ID = (int) $_POST['post_id'];
$lang = $this->model->get_language( sanitize_key( $_POST['lang'] ) ); $lang = $this->model->get_language( sanitize_key( $_POST['lang'] ) );
$post_type = sanitize_key( $_POST['post_type'] ); $post_type = sanitize_key( $_POST['post_type'] );
if ( ! post_type_exists( $post_type ) ) { if ( ! post_type_exists( $post_type ) ) {
...@@ -159,8 +158,9 @@ class PLL_Admin_Classic_Editor { ...@@ -159,8 +158,9 @@ class PLL_Admin_Classic_Editor {
ob_end_clean(); ob_end_clean();
// Categories // Categories
if ( isset( $_POST['taxonomies'] ) ) { if ( isset( $_POST['taxonomies'] ) ) { // Not set for pages
// Not set for pages $supplemental = array();
foreach ( array_map( 'sanitize_key', $_POST['taxonomies'] ) as $taxname ) { foreach ( array_map( 'sanitize_key', $_POST['taxonomies'] ) as $taxname ) {
$taxonomy = get_taxonomy( $taxname ); $taxonomy = get_taxonomy( $taxname );
......
...@@ -21,25 +21,28 @@ class PLL_Admin_Filters_Columns { ...@@ -21,25 +21,28 @@ class PLL_Admin_Filters_Columns {
$this->model = &$polylang->model; $this->model = &$polylang->model;
$this->filter_lang = &$polylang->filter_lang; $this->filter_lang = &$polylang->filter_lang;
// Add the language and translations columns in 'All Posts', 'All Pages' and 'Media library' panels // Hide the column of the filtered language.
add_filter( 'hidden_columns', array( $this, 'hidden_columns' ) ); // Since WP 4.4.
// Add the language and translations columns in 'All Posts', 'All Pages' and 'Media library' panels.
foreach ( $this->model->get_translated_post_types() as $type ) { foreach ( $this->model->get_translated_post_types() as $type ) {
// Use the latest filter late as some plugins purely overwrite what's done by others :( // Use the latest filter late as some plugins purely overwrite what's done by others :(
// Specific case for media // Specific case for media.
add_filter( 'manage_' . ( 'attachment' == $type ? 'upload' : 'edit-' . $type ) . '_columns', array( $this, 'add_post_column' ), 100 ); add_filter( 'manage_' . ( 'attachment' == $type ? 'upload' : 'edit-' . $type ) . '_columns', array( $this, 'add_post_column' ), 100 );
add_action( 'manage_' . ( 'attachment' == $type ? 'media' : $type . '_posts' ) . '_custom_column', array( $this, 'post_column' ), 10, 2 ); add_action( 'manage_' . ( 'attachment' == $type ? 'media' : $type . '_posts' ) . '_custom_column', array( $this, 'post_column' ), 10, 2 );
} }
// Quick edit and bulk edit // Quick edit and bulk edit.
add_filter( 'quick_edit_custom_box', array( $this, 'quick_edit_custom_box' ), 10, 2 ); add_filter( 'quick_edit_custom_box', array( $this, 'quick_edit_custom_box' ), 10, 2 );
add_filter( 'bulk_edit_custom_box', array( $this, 'quick_edit_custom_box' ), 10, 2 ); add_filter( 'bulk_edit_custom_box', array( $this, 'quick_edit_custom_box' ), 10, 2 );
// Adds the language column in the 'Categories' and 'Post Tags' tables // Adds the language column in the 'Categories' and 'Post Tags' tables.
foreach ( $this->model->get_translated_taxonomies() as $tax ) { foreach ( $this->model->get_translated_taxonomies() as $tax ) {
add_filter( 'manage_edit-' . $tax . '_columns', array( $this, 'add_term_column' ) ); add_filter( 'manage_edit-' . $tax . '_columns', array( $this, 'add_term_column' ) );
add_filter( 'manage_' . $tax . '_custom_column', array( $this, 'term_column' ), 10, 3 ); add_filter( 'manage_' . $tax . '_custom_column', array( $this, 'term_column' ), 10, 3 );
} }
// Ajax responses to update list table rows // Ajax responses to update list table rows.
add_action( 'wp_ajax_pll_update_post_rows', array( $this, 'ajax_update_post_rows' ) ); add_action( 'wp_ajax_pll_update_post_rows', array( $this, 'ajax_update_post_rows' ) );
add_action( 'wp_ajax_pll_update_term_rows', array( $this, 'ajax_update_term_rows' ) ); add_action( 'wp_ajax_pll_update_term_rows', array( $this, 'ajax_update_term_rows' ) );
} }
...@@ -60,10 +63,7 @@ class PLL_Admin_Filters_Columns { ...@@ -60,10 +63,7 @@ class PLL_Admin_Filters_Columns {
} }
foreach ( $this->model->get_languages_list() as $language ) { foreach ( $this->model->get_languages_list() as $language ) {
// Don't add the column for the filtered language $columns[ 'language_' . $language->slug ] = $language->flag ? $language->flag . '<span class="screen-reader-text">' . esc_html( $language->name ) . '</span>' : esc_html( $language->slug );
if ( empty( $this->filter_lang ) || $language->slug != $this->filter_lang->slug ) {
$columns[ 'language_' . $language->slug ] = $language->flag ? $language->flag . '<span class="screen-reader-text">' . esc_html( $language->name ) . '</span>' : esc_html( $language->slug );
}
} }
return isset( $end ) ? array_merge( $columns, $end ) : $columns; return isset( $end ) ? array_merge( $columns, $end ) : $columns;
...@@ -77,15 +77,30 @@ class PLL_Admin_Filters_Columns { ...@@ -77,15 +77,30 @@ class PLL_Admin_Filters_Columns {
* @return string first language column name * @return string first language column name
*/ */
protected function get_first_language_column() { protected function get_first_language_column() {
$columns = array();
foreach ( $this->model->get_languages_list() as $language ) { foreach ( $this->model->get_languages_list() as $language ) {
if ( empty( $this->filter_lang ) || $language->slug != $this->filter_lang->slug ) { $columns[] = 'language_' . $language->slug;
$columns[] = 'language_' . $language->slug;
}
} }
return empty( $columns ) ? '' : reset( $columns ); return empty( $columns ) ? '' : reset( $columns );
} }
/**
* Hide the column for the filtered language
*
* @since 2.7
*
* @param array $hidden Array of hidden columns
* @return array
*/
public function hidden_columns( $hidden ) {
if ( ! empty( $this->filter_lang ) ) {
$hidden[] = 'language_' . $this->filter_lang->slug;
}
return $hidden;
}
/** /**
* Adds the language and translations columns ( before the comments column ) in the posts, pages and media library tables * Adds the language and translations columns ( before the comments column ) in the posts, pages and media library tables
* *
...@@ -122,8 +137,6 @@ class PLL_Admin_Filters_Columns { ...@@ -122,8 +137,6 @@ class PLL_Admin_Filters_Columns {
printf( '<div class="hidden" id="lang_%d">%s</div>', intval( $post_id ), esc_html( $lang->slug ) ); printf( '<div class="hidden" id="lang_%d">%s</div>', intval( $post_id ), esc_html( $lang->slug ) );
} }
$post_type_object = get_post_type_object( get_post_type( $post_id ) );
// Link to edit post ( or a translation ) // Link to edit post ( or a translation )
if ( $id = $this->model->post->get( $post_id, $language ) ) { if ( $id = $this->model->post->get( $post_id, $language ) ) {
// get_edit_post_link returns nothing if the user cannot edit the post // get_edit_post_link returns nothing if the user cannot edit the post
...@@ -273,7 +286,7 @@ class PLL_Admin_Filters_Columns { ...@@ -273,7 +286,7 @@ class PLL_Admin_Filters_Columns {
esc_html( $s ) esc_html( $s )
); );
} elseif ( $id === $term_id ) { } elseif ( $id === $term_id ) {
$out .= printf( $out .= sprintf(
'<span class="pll_icon_tick"><span class="screen-reader-text">%s</span></span>', '<span class="pll_icon_tick"><span class="screen-reader-text">%s</span></span>',
/* translators: accessibility text, %s is a native language name */ /* translators: accessibility text, %s is a native language name */
esc_html( sprintf( __( 'This item is in %s', 'polylang' ), $language->name ) ) esc_html( sprintf( __( 'This item is in %s', 'polylang' ), $language->name ) )
......
...@@ -34,6 +34,8 @@ abstract class PLL_Admin_Filters_Post_Base { ...@@ -34,6 +34,8 @@ abstract class PLL_Admin_Filters_Post_Base {
// Security check as 'wp_insert_post' can be called from outside WP admin // Security check as 'wp_insert_post' can be called from outside WP admin
check_admin_referer( 'pll_language', '_pll_nonce' ); check_admin_referer( 'pll_language', '_pll_nonce' );
$translations = array();
// Save translations after checking the translated post is in the right language // Save translations after checking the translated post is in the right language
foreach ( $arr as $lang => $tr_id ) { foreach ( $arr as $lang => $tr_id ) {
$translations[ $lang ] = ( $tr_id && $this->model->post->get_language( (int) $tr_id )->slug == $lang ) ? (int) $tr_id : 0; $translations[ $lang ] = ( $tr_id && $this->model->post->get_language( (int) $tr_id )->slug == $lang ) ? (int) $tr_id : 0;
......
...@@ -47,6 +47,7 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base { ...@@ -47,6 +47,7 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
// Hierarchical taxonomies // Hierarchical taxonomies
if ( 'edit' == $screen->base && $taxonomies = get_object_taxonomies( $screen->post_type, 'object' ) ) { if ( 'edit' == $screen->base && $taxonomies = get_object_taxonomies( $screen->post_type, 'object' ) ) {
// Get translated hierarchical taxonomies // Get translated hierarchical taxonomies
$hierarchical_taxonomies = array();
foreach ( $taxonomies as $taxonomy ) { foreach ( $taxonomies as $taxonomy ) {
if ( $taxonomy->hierarchical && $taxonomy->show_in_quick_edit && $this->model->is_translated_taxonomy( $taxonomy->name ) ) { if ( $taxonomy->hierarchical && $taxonomy->show_in_quick_edit && $this->model->is_translated_taxonomy( $taxonomy->name ) ) {
$hierarchical_taxonomies[] = $taxonomy->name; $hierarchical_taxonomies[] = $taxonomy->name;
...@@ -54,7 +55,8 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base { ...@@ -54,7 +55,8 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
} }
if ( ! empty( $hierarchical_taxonomies ) ) { if ( ! empty( $hierarchical_taxonomies ) ) {
$terms = get_terms( $hierarchical_taxonomies, array( 'get' => 'all' ) ); $terms = get_terms( $hierarchical_taxonomies, array( 'get' => 'all' ) );
$term_languages = array();
foreach ( $terms as $term ) { foreach ( $terms as $term ) {
if ( $lang = $this->model->term->get_language( $term->term_id ) ) { if ( $lang = $this->model->term->get_language( $term->term_id ) ) {
...@@ -71,7 +73,8 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base { ...@@ -71,7 +73,8 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
// Hierarchical post types // Hierarchical post types
if ( 'edit' == $screen->base && is_post_type_hierarchical( $screen->post_type ) ) { if ( 'edit' == $screen->base && is_post_type_hierarchical( $screen->post_type ) ) {
$pages = get_pages(); $pages = get_pages();
$page_languages = array();
foreach ( $pages as $page ) { foreach ( $pages as $page ) {
if ( $lang = $this->model->post->get_language( $page->ID ) ) { if ( $lang = $this->model->post->get_language( $page->ID ) ) {
......
...@@ -133,8 +133,8 @@ class PLL_Admin_Filters_Term { ...@@ -133,8 +133,8 @@ class PLL_Admin_Filters_Term {
return; return;
} }
$term_id = $tag->term_id; $term_id = $tag->term_id;
$taxonomy = $tag->taxonomy; $taxonomy = $tag->taxonomy; // phpcs:ignore WordPressVIPMinimum.Variables.VariableAnalysis.UnusedVariable
$lang = $this->model->term->get_language( $term_id ); $lang = $this->model->term->get_language( $term_id );
$lang = empty( $lang ) ? $this->pref_lang : $lang; $lang = empty( $lang ) ? $this->pref_lang : $lang;
...@@ -271,8 +271,10 @@ class PLL_Admin_Filters_Term { ...@@ -271,8 +271,10 @@ class PLL_Admin_Filters_Term {
// If we have several terms with the same name, they are translations of each other // If we have several terms with the same name, they are translations of each other
if ( count( $terms ) > 1 ) { if ( count( $terms ) > 1 ) {
$translations = array();
foreach ( $terms as $term ) { foreach ( $terms as $term ) {
$translations[ $this->model->term->get_language( $term->term_id )->slug ] = $term->term_id; $translations[ $this->model->term->get_language( $term->term_id )->slug ] = $term->term_id;
} }
$this->model->term->save_translations( $term_id, $translations ); $this->model->term->save_translations( $term_id, $translations );
...@@ -368,7 +370,7 @@ class PLL_Admin_Filters_Term { ...@@ -368,7 +370,7 @@ class PLL_Admin_Filters_Term {
$this->save_language( $term_id, $taxonomy ); $this->save_language( $term_id, $taxonomy );
if ( isset( $_POST['term_tr_lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification if ( isset( $_POST['term_tr_lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$translations = $this->save_translations( $term_id ); $this->save_translations( $term_id );
} }
} }
} }
...@@ -433,9 +435,9 @@ class PLL_Admin_Filters_Term { ...@@ -433,9 +435,9 @@ class PLL_Admin_Filters_Term {
wp_die( 0 ); wp_die( 0 );
} }
$lang = $this->model->get_language( sanitize_key( $_POST['lang'] ) ); $lang = $this->model->get_language( sanitize_key( $_POST['lang'] ) );
$term_id = isset( $_POST['term_id'] ) ? (int) $_POST['term_id'] : null; $term_id = isset( $_POST['term_id'] ) ? (int) $_POST['term_id'] : null; // phpcs:ignore WordPressVIPMinimum.Variables.VariableAnalysis.UnusedVariable
$taxonomy = sanitize_key( $_POST['taxonomy'] ); $taxonomy = sanitize_key( $_POST['taxonomy'] ); // phpcs:ignore WordPressVIPMinimum.Variables.VariableAnalysis.UnusedVariable
$post_type = sanitize_key( $_POST['post_type'] ); $post_type = sanitize_key( $_POST['post_type'] );
if ( ! post_type_exists( $post_type ) || ! taxonomy_exists( $taxonomy ) ) { if ( ! post_type_exists( $post_type ) || ! taxonomy_exists( $taxonomy ) ) {
...@@ -502,7 +504,7 @@ class PLL_Admin_Filters_Term { ...@@ -502,7 +504,7 @@ class PLL_Admin_Filters_Term {
$s = wp_unslash( $_GET['term'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $s = wp_unslash( $_GET['term'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
$post_type = sanitize_key( $_GET['post_type'] ); $post_type = sanitize_key( $_GET['post_type'] );
$taxonomy = sanitize_key( $_GET['taxonomy'] ); $taxonomy = sanitize_key( $_GET['taxonomy'] );
if ( ! post_type_exists( $post_type ) || ! taxonomy_exists( $taxonomy ) ) { if ( ! post_type_exists( $post_type ) || ! taxonomy_exists( $taxonomy ) ) {
wp_die( 0 ); wp_die( 0 );
...@@ -511,32 +513,40 @@ class PLL_Admin_Filters_Term { ...@@ -511,32 +513,40 @@ class PLL_Admin_Filters_Term {
$term_language = $this->model->get_language( sanitize_key( $_GET['term_language'] ) ); $term_language = $this->model->get_language( sanitize_key( $_GET['term_language'] ) );
$translation_language = $this->model->get_language( sanitize_key( $_GET['translation_language'] ) ); $translation_language = $this->model->get_language( sanitize_key( $_GET['translation_language'] ) );
$terms = array();
$return = array(); $return = array();
// It is more efficient to use one common query for all languages as soon as there are more than 2 // Add current translation in list.
// Not in add term as term_id is not set.
if ( isset( $_GET['term_id'] ) && 'undefined' !== $_GET['term_id'] && $term_id = $this->model->term->get_translation( (int) $_GET['term_id'], $translation_language ) ) {
$terms = array( get_term( $term_id, $taxonomy ) );
}
// It is more efficient to use one common query for all languages as soon as there are more than 2.
foreach ( get_terms( $taxonomy, 'hide_empty=0&lang=0&name__like=' . $s ) as $term ) { foreach ( get_terms( $taxonomy, 'hide_empty=0&lang=0&name__like=' . $s ) as $term ) {
$lang = $this->model->term->get_language( $term->term_id ); $lang = $this->model->term->get_language( $term->term_id );
if ( $lang && $lang->slug == $translation_language->slug && ! $this->model->term->get_translation( $term->term_id, $term_language ) ) { if ( $lang && $lang->slug == $translation_language->slug && ! $this->model->term->get_translation( $term->term_id, $term_language ) ) {
$return[] = array( $terms[] = $term;
'id' => $term->term_id,
'value' => $term->name,
'link' => $this->links->edit_term_translation_link( $term->term_id, $taxonomy, $post_type ),
);
} }
} }
// Add current translation in list // Format the ajax response.
// Not in add term as term_id is not set foreach ( $terms as $term ) {
if ( isset( $_GET['term_id'] ) && 'undefined' !== $_GET['term_id'] && $term_id = $this->model->term->get_translation( (int) $_GET['term_id'], $translation_language ) ) { $return[] = array(
$term = get_term( $term_id, $taxonomy ); 'id' => $term->term_id,
array_unshift( 'value' => rtrim( // Trim the seperator added at the end by WP.
$return, get_term_parents_list(
array( $term->term_id,
'id' => $term_id, $term->taxonomy,
'value' => $term->name, array(
'link' => $this->links->edit_term_translation_link( $term->term_id, $taxonomy, $post_type ), 'separator' => ' > ',
) 'link' => false,
)
),
' >'
),
'link' => $this->links->edit_term_translation_link( $term->term_id, $term->taxonomy, $post_type ),
); );
} }
...@@ -607,6 +617,7 @@ class PLL_Admin_Filters_Term { ...@@ -607,6 +617,7 @@ class PLL_Admin_Filters_Term {
$avoid_recursion = true; $avoid_recursion = true;
$lang = $this->model->term->get_language( $term_id ); $lang = $this->model->term->get_language( $term_id );
$translations = array();
foreach ( $this->model->term->get_translations( $term_id ) as $key => $tr_id ) { foreach ( $this->model->term->get_translations( $term_id ) as $key => $tr_id ) {
if ( $lang->slug == $key ) { if ( $lang->slug == $key ) {
......
...@@ -42,6 +42,9 @@ class PLL_Admin_Filters extends PLL_Filters { ...@@ -42,6 +42,9 @@ class PLL_Admin_Filters extends PLL_Filters {
} }
add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) ); add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
// Add post state for translations of the privacy policy page
add_filter( 'display_post_states', array( $this, 'display_post_states' ), 10, 2 );
} }
/** /**
...@@ -265,4 +268,23 @@ class PLL_Admin_Filters extends PLL_Filters { ...@@ -265,4 +268,23 @@ class PLL_Admin_Filters extends PLL_Filters {
} }
return $classes; return $classes;
} }
/**
* Add post state for translations of the privacy policy page
*
* @since 2.7
*
* @param array $post_states An array of post display states.
* @param object $post The current post object.
* @return array
*/
public function display_post_states( $post_states, $post ) {
$page_for_privacy_policy = get_option( 'wp_page_for_privacy_policy' );
if ( $page_for_privacy_policy && in_array( $post->ID, $this->model->post->get_translations( $page_for_privacy_policy ) ) ) {
$post_states['page_for_privacy_policy'] = __( 'Privacy Policy Page', 'polylang' );
}
return $post_states;
}
} }
...@@ -125,7 +125,7 @@ class PLL_Admin_Model extends PLL_Model { ...@@ -125,7 +125,7 @@ class PLL_Admin_Model extends PLL_Model {
// Delete menus locations // Delete menus locations
if ( ! empty( $this->options['nav_menus'] ) ) { if ( ! empty( $this->options['nav_menus'] ) ) {
foreach ( $this->options['nav_menus'] as $theme => $locations ) { foreach ( $this->options['nav_menus'] as $theme => $locations ) {
foreach ( $locations as $location => $languages ) { foreach ( array_keys( $locations ) as $location ) {
unset( $this->options['nav_menus'][ $theme ][ $location ][ $lang->slug ] ); unset( $this->options['nav_menus'][ $theme ][ $location ][ $lang->slug ] );
} }
} }
...@@ -211,7 +211,7 @@ class PLL_Admin_Model extends PLL_Model { ...@@ -211,7 +211,7 @@ class PLL_Admin_Model extends PLL_Model {
// Update menus locations // Update menus locations
if ( ! empty( $this->options['nav_menus'] ) ) { if ( ! empty( $this->options['nav_menus'] ) ) {
foreach ( $this->options['nav_menus'] as $theme => $locations ) { foreach ( $this->options['nav_menus'] as $theme => $locations ) {
foreach ( $locations as $location => $languages ) { foreach ( array_keys( $locations ) as $location ) {
if ( ! empty( $this->options['nav_menus'][ $theme ][ $location ][ $old_slug ] ) ) { if ( ! empty( $this->options['nav_menus'][ $theme ][ $location ][ $old_slug ] ) ) {
$this->options['nav_menus'][ $theme ][ $location ][ $slug ] = $this->options['nav_menus'][ $theme ][ $location ][ $old_slug ]; $this->options['nav_menus'][ $theme ][ $location ][ $slug ] = $this->options['nav_menus'][ $theme ][ $location ][ $old_slug ];
unset( $this->options['nav_menus'][ $theme ][ $location ][ $old_slug ] ); unset( $this->options['nav_menus'][ $theme ][ $location ][ $old_slug ] );
...@@ -318,9 +318,10 @@ class PLL_Admin_Model extends PLL_Model { ...@@ -318,9 +318,10 @@ class PLL_Admin_Model extends PLL_Model {
public function set_language_in_mass( $type, $ids, $lang ) { public function set_language_in_mass( $type, $ids, $lang ) {
global $wpdb; global $wpdb;
$ids = array_map( 'intval', $ids ); $ids = array_map( 'intval', $ids );
$lang = $this->get_language( $lang ); $lang = $this->get_language( $lang );
$tt_id = 'term' === $type ? $lang->tl_term_taxonomy_id : $lang->term_taxonomy_id; $tt_id = 'term' === $type ? $lang->tl_term_taxonomy_id : $lang->term_taxonomy_id;
$values = array();
foreach ( $ids as $id ) { foreach ( $ids as $id ) {
$values[] = $wpdb->prepare( '( %d, %d )', $id, $tt_id ); $values[] = $wpdb->prepare( '( %d, %d )', $id, $tt_id );
...@@ -334,6 +335,7 @@ class PLL_Admin_Model extends PLL_Model { ...@@ -334,6 +335,7 @@ class PLL_Admin_Model extends PLL_Model {
if ( 'term' === $type ) { if ( 'term' === $type ) {
clean_term_cache( $ids, 'term_language' ); clean_term_cache( $ids, 'term_language' );
$translations = array();
foreach ( $ids as $id ) { foreach ( $ids as $id ) {
$translations[] = array( $lang->slug => $id ); $translations[] = array( $lang->slug => $id );
...@@ -358,7 +360,11 @@ class PLL_Admin_Model extends PLL_Model { ...@@ -358,7 +360,11 @@ class PLL_Admin_Model extends PLL_Model {
public function set_translation_in_mass( $type, $translations ) { public function set_translation_in_mass( $type, $translations ) {
global $wpdb; global $wpdb;
$taxonomy = $type . '_translations'; $taxonomy = $type . '_translations';
$terms = array();
$slugs = array();
$description = array();
$count = array();
foreach ( $translations as $t ) { foreach ( $translations as $t ) {
$term = uniqid( 'pll_' ); // the term name $term = uniqid( 'pll_' ); // the term name
...@@ -376,7 +382,9 @@ class PLL_Admin_Model extends PLL_Model { ...@@ -376,7 +382,9 @@ class PLL_Admin_Model extends PLL_Model {
// Get all terms with their term_id // Get all terms with their term_id
// PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
$terms = $wpdb->get_results( "SELECT term_id, slug FROM {$wpdb->terms} WHERE slug IN ( " . implode( ',', $slugs ) . ' )' ); $terms = $wpdb->get_results( "SELECT term_id, slug FROM {$wpdb->terms} WHERE slug IN ( " . implode( ',', $slugs ) . ' )' );
$term_ids = array();
$tts = array();
// Prepare terms taxonomy relationship // Prepare terms taxonomy relationship
foreach ( $terms as $term ) { foreach ( $terms as $term ) {
...@@ -392,6 +400,7 @@ class PLL_Admin_Model extends PLL_Model { ...@@ -392,6 +400,7 @@ class PLL_Admin_Model extends PLL_Model {
// Get all terms with term_taxonomy_id // Get all terms with term_taxonomy_id
$terms = get_terms( $taxonomy, array( 'hide_empty' => false ) ); $terms = get_terms( $taxonomy, array( 'hide_empty' => false ) );
$trs = array();
// Prepare objects relationships // Prepare objects relationships
foreach ( $terms as $term ) { foreach ( $terms as $term ) {
...@@ -492,7 +501,11 @@ class PLL_Admin_Model extends PLL_Model { ...@@ -492,7 +501,11 @@ class PLL_Admin_Model extends PLL_Model {
public function update_translations( $old_slug, $new_slug = '' ) { public function update_translations( $old_slug, $new_slug = '' ) {
global $wpdb; global $wpdb;
$terms = get_terms( array( 'post_translations', 'term_translations' ) ); $terms = get_terms( array( 'post_translations', 'term_translations' ) );
$term_ids = array();
$dr = array();
$dt = array();
$ut = array();
foreach ( $terms as $term ) { foreach ( $terms as $term ) {
$term_ids[ $term->taxonomy ][] = $term->term_id; $term_ids[ $term->taxonomy ][] = $term->term_id;
...@@ -563,6 +576,8 @@ class PLL_Admin_Model extends PLL_Model { ...@@ -563,6 +576,8 @@ class PLL_Admin_Model extends PLL_Model {
// The nav menus stored in theme locations should be in the default language // The nav menus stored in theme locations should be in the default language
$theme = get_stylesheet(); $theme = get_stylesheet();
if ( ! empty( $this->options['nav_menus'][ $theme ] ) ) { if ( ! empty( $this->options['nav_menus'][ $theme ] ) ) {
$menus = array();
foreach ( $this->options['nav_menus'][ $theme ] as $key => $loc ) { foreach ( $this->options['nav_menus'][ $theme ] as $key => $loc ) {
$menus[ $key ] = empty( $loc[ $slug ] ) ? 0 : $loc[ $slug ]; $menus[ $key ] = empty( $loc[ $slug ] ) ? 0 : $loc[ $slug ];
} }
......
...@@ -94,8 +94,11 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu { ...@@ -94,8 +94,11 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
wp_enqueue_script( 'pll_nav_menu', plugins_url( '/js/nav-menu' . $suffix . '.js', POLYLANG_FILE ), array( 'jquery' ), POLYLANG_VERSION ); wp_enqueue_script( 'pll_nav_menu', plugins_url( '/js/nav-menu' . $suffix . '.js', POLYLANG_FILE ), array( 'jquery' ), POLYLANG_VERSION );
$data['strings'] = PLL_Switcher::get_switcher_options( 'menu', 'string' ); // The strings for the options $data = array(
$data['title'] = __( 'Languages', 'polylang' ); // The title 'strings' => PLL_Switcher::get_switcher_options( 'menu', 'string' ), // The strings for the options
'title' => __( 'Languages', 'polylang' ), // The title
'val' => array(),
);
// Get all language switcher menu items // Get all language switcher menu items
$items = get_posts( $items = get_posts(
...@@ -109,7 +112,6 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu { ...@@ -109,7 +112,6 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
); );
// The options values for the language switcher // The options values for the language switcher
$data['val'] = array();
foreach ( $items as $item ) { foreach ( $items as $item ) {
$data['val'][ $item ] = get_post_meta( $item, '_pll_menu_item', true ); $data['val'][ $item ] = get_post_meta( $item, '_pll_menu_item', true );
} }
...@@ -143,7 +145,7 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu { ...@@ -143,7 +145,7 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
} }
} }
else { else {
foreach ( $options as $opt => $v ) { foreach ( array_keys( $options ) as $opt ) {
$options[ $opt ] = empty( $_POST[ 'menu-item-' . $opt ][ $menu_item_db_id ] ) ? 0 : 1; $options[ $opt ] = empty( $_POST[ 'menu-item-' . $opt ][ $menu_item_db_id ] ) ? 0 : 1;
} }
update_post_meta( $menu_item_db_id, '_pll_menu_item', $options ); // Allow us to easily identify our nav menu item update_post_meta( $menu_item_db_id, '_pll_menu_item', $options ); // Allow us to easily identify our nav menu item
...@@ -160,8 +162,6 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu { ...@@ -160,8 +162,6 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
* @return array * @return array
*/ */
public function update_nav_menu_locations( $locations ) { public function update_nav_menu_locations( $locations ) {
$default = $this->options['default_lang'];
// Extract language and menu from locations // Extract language and menu from locations
foreach ( $locations as $loc => $menu ) { foreach ( $locations as $loc => $menu ) {
$infos = $this->explode_location( $loc ); $infos = $this->explode_location( $loc );
...@@ -232,7 +232,7 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu { ...@@ -232,7 +232,7 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
} }
if ( is_array( $menus ) ) { if ( is_array( $menus ) ) {
foreach ( $menus as $loc => $menu ) { foreach ( array_keys( $menus ) as $loc ) {
foreach ( $this->model->get_languages_list() as $lang ) { foreach ( $this->model->get_languages_list() as $lang ) {
if ( ! empty( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ] ) && term_exists( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ], 'nav_menu' ) ) { if ( ! empty( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ] ) && term_exists( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ], 'nav_menu' ) ) {
$menus[ $this->combine_location( $loc, $lang ) ] = $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ]; $menus[ $this->combine_location( $loc, $lang ) ] = $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ];
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* and only on dashboard, plugins and Polylang admin pages * and only on dashboard, plugins and Polylang admin pages
* *
* @since 2.3.9 * @since 2.3.9
* @since 2.7 Dismissed notices are stored in an option instead of a user meta
*/ */
class PLL_Admin_Notices { class PLL_Admin_Notices {
private static $notices = array(); private static $notices = array();
...@@ -57,8 +58,22 @@ class PLL_Admin_Notices { ...@@ -57,8 +58,22 @@ class PLL_Admin_Notices {
* @return bool * @return bool
*/ */
public static function is_dismissed( $notice ) { public static function is_dismissed( $notice ) {
$dismissed = get_user_meta( get_current_user_id(), 'pll_dismissed_notices', true ); $dismissed = get_option( 'pll_dismissed_notices', array() );
return is_array( $dismissed ) && in_array( $notice, $dismissed );
// Handle legacy user meta
$dismissed_meta = get_user_meta( get_current_user_id(), 'pll_dismissed_notices', true );
if ( is_array( $dismissed_meta ) ) {
if ( array_diff( $dismissed_meta, $dismissed ) ) {
$dismissed = array_merge( $dismissed, $dismissed_meta );
update_option( 'pll_dismissed_notices', $dismissed );
}
if ( ! is_multisite() ) {
// Don't delete on multisite to avoid the notices to appear in other sites.
delete_user_meta( get_current_user_id(), 'pll_dismissed_notices' );
}
}
return in_array( $notice, $dismissed );
} }
/** /**
...@@ -66,21 +81,34 @@ class PLL_Admin_Notices { ...@@ -66,21 +81,34 @@ class PLL_Admin_Notices {
* *
* @since 2.3.9 * @since 2.3.9
* *
* @param string $notice The notice name.
* @return bool * @return bool
*/ */
protected function can_display_notice() { protected function can_display_notice( $notice ) {
$screen = get_current_screen(); $screen = get_current_screen();
$screen_id = sanitize_title( __( 'Languages', 'polylang' ) ); $screen_id = sanitize_title( __( 'Languages', 'polylang' ) );
return in_array( /**
$screen->id, * Filter admin notices which can be displayed
array( *
'dashboard', * @since 2.7.0
'plugins', *
'toplevel_page_mlang', * @param bool $display Whether the notice should be displayed or not.
$screen_id . '_page_mlang_strings', * @param string $notice The notice name.
$screen_id . '_page_mlang_settings', */
) return apply_filters(
'pll_can_display_notice',
in_array(
$screen->id,
array(
'dashboard',
'plugins',
'toplevel_page_mlang',
$screen_id . '_page_mlang_strings',
$screen_id . '_page_mlang_settings',
)
),
$notice
); );
} }
...@@ -92,13 +120,11 @@ class PLL_Admin_Notices { ...@@ -92,13 +120,11 @@ class PLL_Admin_Notices {
* @param string $notice * @param string $notice
*/ */
public static function dismiss( $notice ) { public static function dismiss( $notice ) {
if ( ! $dismissed = get_user_meta( get_current_user_id(), 'pll_dismissed_notices', true ) ) { $dismissed = get_option( 'pll_dismissed_notices', array() );
$dismissed = array();
}
if ( ! in_array( $notice, $dismissed ) ) { if ( ! in_array( $notice, $dismissed ) ) {
$dismissed[] = $notice; $dismissed[] = $notice;
update_user_meta( get_current_user_id(), 'pll_dismissed_notices', array_unique( $dismissed ) ); update_option( 'pll_dismissed_notices', array_unique( $dismissed ) );
} }
} }
...@@ -123,14 +149,19 @@ class PLL_Admin_Notices { ...@@ -123,14 +149,19 @@ class PLL_Admin_Notices {
* @since 2.3.9 * @since 2.3.9
*/ */
public function display_notices() { public function display_notices() {
if ( current_user_can( 'manage_options' ) && $this->can_display_notice() ) { if ( current_user_can( 'manage_options' ) ) {
// Core notices // Core notices
$this->pllwc_notice(); if ( defined( 'WOOCOMMERCE_VERSION' ) && ! defined( 'PLLWC_VERSION' ) && $this->can_display_notice( 'pllwc' ) && ! $this->is_dismissed( 'pllwc' ) ) {
$this->review_notice(); $this->pllwc_notice();
}
if ( ! defined( 'POLYLANG_PRO' ) && $this->can_display_notice( 'review' ) && ! $this->is_dismissed( 'review' ) && ! empty( $this->options['first_activation'] ) && time() > $this->options['first_activation'] + 15 * DAY_IN_SECONDS ) {
$this->review_notice();
}
// Custom notices // Custom notices
foreach ( $this->get_notices() as $notice => $html ) { foreach ( $this->get_notices() as $notice => $html ) {
if ( ! $this->is_dismissed( $notice ) ) { if ( $this->can_display_notice( $notice ) && ! $this->is_dismissed( $notice ) ) {
?> ?>
<div class="pll-notice notice notice-info"> <div class="pll-notice notice notice-info">
<?php <?php
...@@ -166,23 +197,21 @@ class PLL_Admin_Notices { ...@@ -166,23 +197,21 @@ class PLL_Admin_Notices {
* @since 2.3.9 * @since 2.3.9
*/ */
private function pllwc_notice() { private function pllwc_notice() {
if ( defined( 'WOOCOMMERCE_VERSION' ) && ! defined( 'PLLWC_VERSION' ) && ! $this->is_dismissed( 'pllwc' ) ) { ?>
?> <div class="pll-notice notice notice-warning">
<div class="pll-notice notice notice-warning"> <?php $this->dismiss_button( 'pllwc' ); ?>
<?php $this->dismiss_button( 'pllwc' ); ?> <p>
<p> <?php
<?php printf(
printf( /* translators: %1$s is link start tag, %2$s is link end tag. */
/* translators: %1$s is link start tag, %2$s is link end tag. */ esc_html__( 'We have noticed that you are using Polylang with WooCommerce. To ensure compatibility, we recommend you use %1$sPolylang for WooCommerce%2$s.', 'polylang' ),
esc_html__( 'We have noticed that you are using Polylang with WooCommerce. To ensure compatibility, we recommend you use %1$sPolylang for WooCommerce%2$s.', 'polylang' ), '<a href="https://polylang.pro/downloads/polylang-for-woocommerce/">',
'<a href="https://polylang.pro/downloads/polylang-for-woocommerce/">', '</a>'
'</a>' );
); ?>
?> </p>
</p> </div>
</div> <?php
<?php
}
} }
/** /**
...@@ -191,22 +220,20 @@ class PLL_Admin_Notices { ...@@ -191,22 +220,20 @@ class PLL_Admin_Notices {
* @since 2.3.9 * @since 2.3.9
*/ */
private function review_notice() { private function review_notice() {
if ( ! defined( 'POLYLANG_PRO' ) && ! $this->is_dismissed( 'review' ) && ! empty( $this->options['first_activation'] ) && time() > $this->options['first_activation'] + 15 * DAY_IN_SECONDS ) { ?>
?> <div class="pll-notice notice notice-info">
<div class="pll-notice notice notice-info"> <?php $this->dismiss_button( 'review' ); ?>
<?php $this->dismiss_button( 'review' ); ?> <p>
<p> <?php
<?php printf(
printf( /* translators: %1$s is link start tag, %2$s is link end tag. */
/* translators: %1$s is link start tag, %2$s is link end tag. */ esc_html__( 'We have noticed that you have been using Polylang for some time. We hope you love it, and we would really appreciate it if you would %1$sgive us a 5 stars rating%2$s.', 'polylang' ),
esc_html__( 'We have noticed that you have been using Polylang for some time. We hope you love it, and we would really appreciate it if you would %1$sgive us a 5 stars rating%2$s.', 'polylang' ), '<a href="https://wordpress.org/support/plugin/polylang/reviews/?rate=5#new-post">',
'<a href="https://wordpress.org/support/plugin/polylang/reviews/?rate=5#new-post">', '</a>'
'</a>' );
); ?>
?> </p>
</p> </div>
</div> <?php
<?php
}
} }
} }
...@@ -86,8 +86,8 @@ class PLL_Admin_Static_Pages extends PLL_Static_Pages { ...@@ -86,8 +86,8 @@ class PLL_Admin_Static_Pages extends PLL_Static_Pages {
* *
* @since 1.8 * @since 1.8
* *
* @param array $post_states * @param array $post_states An array of post display states.
* @param object $post * @param object $post The current post object.
* @return array * @return array
*/ */
public function display_post_states( $post_states, $post ) { public function display_post_states( $post_states, $post ) {
......
...@@ -118,7 +118,6 @@ class PLL_Admin_Strings { ...@@ -118,7 +118,6 @@ class PLL_Admin_Strings {
* @return string * @return string
*/ */
public static function sanitize_string_translation( $translation, $name ) { public static function sanitize_string_translation( $translation, $name ) {
$translation = wp_unslash( trim( $translation ) );
if ( false !== ( $option = array_search( $name, self::$default_strings['options'], true ) ) ) { if ( false !== ( $option = array_search( $name, self::$default_strings['options'], true ) ) ) {
$translation = sanitize_option( $option, $translation ); $translation = sanitize_option( $option, $translation );
......
...@@ -25,8 +25,12 @@ ...@@ -25,8 +25,12 @@
* block_editor => reference to PLL_Admin_Block_Editor object * block_editor => reference to PLL_Admin_Block_Editor object
* classic_editor => reference to PLL_Admin_Classic_Editor object * classic_editor => reference to PLL_Admin_Classic_Editor object
* filters_media => optional, reference to PLL_Admin_Filters_Media object * filters_media => optional, reference to PLL_Admin_Filters_Media object
* bulk_translate => reference, a PLL_Bulk_Translate subclass instance
* wizard => reference, a PLL_Wizard object
* *
* @since 1.2 * @since 1.2
* @since 2.7 Added a reference to a PLL_Bulk_Translate instance.
* @since 2.7 Added a reference to a PLL_Wizard object.
*/ */
class PLL_Admin extends PLL_Admin_Base { class PLL_Admin extends PLL_Admin_Base {
public $filters, $filters_columns, $filters_post, $filters_term, $nav_menu, $sync, $filters_media; public $filters, $filters_columns, $filters_post, $filters_term, $nav_menu, $sync, $filters_media;
...@@ -61,11 +65,6 @@ class PLL_Admin extends PLL_Admin_Base { ...@@ -61,11 +65,6 @@ class PLL_Admin extends PLL_Admin_Base {
if ( $this->model->get_languages_list() ) { if ( $this->model->get_languages_list() ) {
add_action( 'wp_loaded', array( $this, 'add_filters' ), 5 ); add_action( 'wp_loaded', array( $this, 'add_filters' ), 5 );
add_action( 'admin_init', array( $this, 'maybe_load_sync_post' ), 20 ); // After fusion Builder. add_action( 'admin_init', array( $this, 'maybe_load_sync_post' ), 20 ); // After fusion Builder.
// Bulk Translate
if ( class_exists( 'PLL_Bulk_Translate' ) ) {
add_action( 'current_screen', array( $this->bulk_translate = new PLL_Bulk_Translate( $this ), 'init' ) );
}
} }
} }
...@@ -100,6 +99,7 @@ class PLL_Admin extends PLL_Admin_Base { ...@@ -100,6 +99,7 @@ class PLL_Admin extends PLL_Admin_Base {
* Setup filters for admin pages * Setup filters for admin pages
* *
* @since 1.2 * @since 1.2
* @since 2.7 instantiate a PLL_Bulk_Translate instance.
*/ */
public function add_filters() { public function add_filters() {
// All these are separated just for convenience and maintainability // All these are separated just for convenience and maintainability
...@@ -127,6 +127,13 @@ class PLL_Admin extends PLL_Admin_Base { ...@@ -127,6 +127,13 @@ class PLL_Admin extends PLL_Admin_Base {
$this->posts = new PLL_CRUD_Posts( $this ); $this->posts = new PLL_CRUD_Posts( $this );
$this->terms = new PLL_CRUD_Terms( $this ); $this->terms = new PLL_CRUD_Terms( $this );
// Bulk Translate
// Needs to be loaded before other modules.
if ( class_exists( 'PLL_Bulk_Translate' ) ) {
$this->bulk_translate = new PLL_Bulk_Translate( $this->model );
add_action( 'current_screen', array( $this->bulk_translate, 'init' ) );
}
// Advanced media // Advanced media
if ( $this->options['media_support'] && class_exists( 'PLL_Admin_Advanced_Media' ) ) { if ( $this->options['media_support'] && class_exists( 'PLL_Admin_Advanced_Media' ) ) {
$this->advanced_media = new PLL_Admin_Advanced_Media( $this ); $this->advanced_media = new PLL_Admin_Advanced_Media( $this );
...@@ -146,6 +153,10 @@ class PLL_Admin extends PLL_Admin_Base { ...@@ -146,6 +153,10 @@ class PLL_Admin extends PLL_Admin_Base {
$this->duplicate_rest = new PLL_Duplicate_REST(); $this->duplicate_rest = new PLL_Duplicate_REST();
} }
if ( class_exists( 'PLL_Sync_Post_Model' ) ) {
$this->sync_post_model = new PLL_Sync_Post_Model( $this );
}
// Block editor metabox // Block editor metabox
if ( pll_use_block_editor_plugin() ) { if ( pll_use_block_editor_plugin() ) {
$this->block_editor_plugin = new PLL_Block_Editor_Plugin( $this ); $this->block_editor_plugin = new PLL_Block_Editor_Plugin( $this );
......
...@@ -21,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) { ...@@ -21,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<td class = "pll-media-language-column"><span class = "pll-translation-flag"><?php echo $language->flag; // phpcs:ignore WordPress.Security.EscapeOutput ?></span><?php echo esc_html( $language->name ); ?></td> <td class = "pll-media-language-column"><span class = "pll-translation-flag"><?php echo $language->flag; // phpcs:ignore WordPress.Security.EscapeOutput ?></span><?php echo esc_html( $language->name ); ?></td>
<td class = "pll-media-edit-column"> <td class = "pll-media-edit-column">
<?php <?php
if ( ( $translation_id = $this->model->post->get_translation( $post_id, $language ) ) && $translation_id !== $post_id ) { if ( ( $translation_id = $this->model->post->get_translation( $post_ID, $language ) ) && $translation_id !== $post_ID ) {
// The translation exists // The translation exists
printf( printf(
'<input type="hidden" name="media_tr_lang[%s]" value="%d" />', '<input type="hidden" name="media_tr_lang[%s]" value="%d" />',
...@@ -31,7 +31,7 @@ if ( ! defined( 'ABSPATH' ) ) { ...@@ -31,7 +31,7 @@ if ( ! defined( 'ABSPATH' ) ) {
echo $this->links->edit_post_translation_link( $translation_id ); // phpcs:ignore WordPress.Security.EscapeOutput echo $this->links->edit_post_translation_link( $translation_id ); // phpcs:ignore WordPress.Security.EscapeOutput
} else { } else {
// No translation // No translation
echo $this->links->new_post_translation_link( $post_id, $language ); // phpcs:ignore WordPress.Security.EscapeOutput echo $this->links->new_post_translation_link( $post_ID, $language ); // phpcs:ignore WordPress.Security.EscapeOutput
} }
?> ?>
</td> </td>
......
...@@ -21,6 +21,14 @@ ...@@ -21,6 +21,14 @@
font-family: 'dashicons'; font-family: 'dashicons';
content: "\f155"; content: "\f155";
} }
.pll-icon:before{
display: inline-block;
text-align: left;
width: 15px;
}
.pll-circle:before{
content: "\25cf";
}
.form-field input[type="radio"] { .form-field input[type="radio"] {
width: auto; width: auto;
...@@ -324,6 +332,10 @@ td[class*='column-language_'] { ...@@ -324,6 +332,10 @@ td[class*='column-language_'] {
text-decoration: none; text-decoration: none;
} }
.pll-notice .button {
margin-right: 10px;
}
/* Bulk translate */ /* Bulk translate */
.bulk-translate-save .button { .bulk-translate-save .button {
margin-right: 20px; margin-right: 20px;
...@@ -340,8 +352,8 @@ td[class*='column-language_'] { ...@@ -340,8 +352,8 @@ td[class*='column-language_'] {
#pll-translate .title { #pll-translate .title {
display: block; display: block;
margin: 0.2em 0; margin: 0.2em 0;
line-height: 2.5; line-height: 2.5;
} }
@media screen and ( max-width: 782px ) { @media screen and ( max-width: 782px ) {
......
...@@ -24,11 +24,17 @@ ...@@ -24,11 +24,17 @@
position: relative; position: relative;
margin: 0; margin: 0;
padding: 3px 1em 3px .4em; padding: 3px 1em 3px .4em;
cursor: pointer;
min-height: 0; /* support: IE7 */ min-height: 0; /* support: IE7 */
/* support: IE10, see #8844 */ /* support: IE10, see #8844 */
list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"); list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
} }
.rtl .ui-menu .ui-menu-item {
text-align: right;
}
/* icon support */ /* icon support */
.ui-menu-icons { .ui-menu-icons {
position: relative; position: relative;
...@@ -37,6 +43,10 @@ ...@@ -37,6 +43,10 @@
.ui-menu-icons .ui-menu-item { .ui-menu-icons .ui-menu-item {
padding-left: 2em; padding-left: 2em;
} }
.rtl .ui-menu-icons .ui-menu-item {
padding-left: 1em;
padding-right: 2em;
}
/* left-aligned */ /* left-aligned */
.ui-selectmenu-text .ui-icon, .ui-selectmenu-text .ui-icon,
...@@ -44,10 +54,16 @@ ...@@ -44,10 +54,16 @@
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
left: .2em; left: .3em;
margin: auto 0; margin: auto 0;
} }
.rtl .ui-selectmenu-text .ui-icon,
.rtl .ui-menu .ui-icon {
right: .3em;
left: auto;
}
/* right-aligned */ /* right-aligned */
.ui-menu .ui-menu-icon { .ui-menu .ui-menu-icon {
left: auto; left: auto;
...@@ -97,8 +113,15 @@ ...@@ -97,8 +113,15 @@
margin-top: -10px; margin-top: -10px;
position: absolute; position: absolute;
top: 50%; top: 50%;
text-indent: 0; /* due to text-indent for jquery ui-dialog in wizard */
}
.rtl .ui-selectmenu-button span.ui-icon {
left: 0.5em;
right: auto;
} }
.ui-selectmenu-button span.ui-selectmenu-text { .ui-selectmenu-button span.ui-selectmenu-text {
text-align: left; text-align: left;
padding: 0.2em 2.1em 0.2em 2em; padding: 0.2em 2.1em 0.2em 2em;
...@@ -109,6 +132,11 @@ ...@@ -109,6 +132,11 @@
white-space: nowrap; white-space: nowrap;
} }
.rtl .ui-selectmenu-button span.ui-selectmenu-text {
text-align: right;
padding: 0.2em 2em 0.2em 2.1em;
}
.ui-widget-content, .ui-widget-content,
.ui-state-default, .ui-state-default,
.ui-widget-content .ui-state-default, .ui-widget-content .ui-state-default,
......
.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;min-height:0;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon,.ui-selectmenu-text .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:700;line-height:23px;padding:2px .4em;margin:.5em 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none}.ui-selectmenu-button span.ui-icon{right:.5em;left:auto;margin-top:-10px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:.2em 2.1em .2em 2em;display:block;line-height:23px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-state-default,.ui-widget-content,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{background:#fff;border:1px solid #ddd;box-shadow:0 1px 2px rgba(0,0,0,.07) inset;color:#32373c}.ui-widget-content .ui-state-focus,.ui-widget-content .ui-state-hover{background:#f5f5f5}.ui-selectmenu-button.ui-state-focus{border:1px solid #5b9dd9;box-shadow:0 0 2px rgba(30,140,190,.8)}.ui-icon-triangle-1-s:before{content:"\f140";font:20px/1 dashicons}.ui-widget-content{max-height:231px;box-shadow:0 2px 6px rgba(100,100,100,.3)} .ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;cursor:pointer;min-height:0;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.rtl .ui-menu .ui-menu-item{text-align:right}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.rtl .ui-menu-icons .ui-menu-item{padding-left:1em;padding-right:2em}.ui-menu .ui-icon,.ui-selectmenu-text .ui-icon{position:absolute;top:0;bottom:0;left:.3em;margin:auto 0}.rtl .ui-menu .ui-icon,.rtl .ui-selectmenu-text .ui-icon{right:.3em;left:auto}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:700;line-height:23px;padding:2px .4em;margin:.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none}.ui-selectmenu-button span.ui-icon{right:.5em;left:auto;margin-top:-10px;position:absolute;top:50%;text-indent:0}.rtl .ui-selectmenu-button span.ui-icon{left:.5em;right:auto}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:.2em 2.1em .2em 2em;display:block;line-height:23px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rtl .ui-selectmenu-button span.ui-selectmenu-text{text-align:right;padding:.2em 2em .2em 2.1em}.ui-state-default,.ui-widget-content,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{background:#fff;border:1px solid #ddd;box-shadow:0 1px 2px rgba(0,0,0,.07) inset;color:#32373c}.ui-widget-content .ui-state-focus,.ui-widget-content .ui-state-hover{background:#f5f5f5}.ui-selectmenu-button.ui-state-focus{border:1px solid #5b9dd9;box-shadow:0 0 2px rgba(30,140,190,.8)}.ui-icon-triangle-1-s:before{content:"\f140";font:20px/1 dashicons}.ui-widget-content{max-height:231px;box-shadow:0 2px 6px rgba(100,100,100,.3)}
...@@ -191,16 +191,25 @@ abstract class PLL_Choose_Lang { ...@@ -191,16 +191,25 @@ abstract class PLL_Choose_Lang {
} }
/** /**
* Returns the language according to browser preference or the default language * Returns the preferred language
* either from the cookie if it's a returning visit
* or according to browser preference
* or the default language
* *
* @since 0.1 * @since 0.1
* *
* @return object browser preferred language or default language * @return object browser preferred language or default language
*/ */
public function get_preferred_language() { public function get_preferred_language() {
// check first if the user was already browsing this site $language = false;
$cookie = false;
if ( isset( $_COOKIE[ PLL_COOKIE ] ) ) { if ( isset( $_COOKIE[ PLL_COOKIE ] ) ) {
return $this->model->get_language( sanitize_key( $_COOKIE[ PLL_COOKIE ] ) ); // Check first if the user was already browsing this site.
$language = sanitize_key( $_COOKIE[ PLL_COOKIE ] );
$cookie = true;
} elseif ( $this->options['browser'] ) {
$language = $this->get_preferred_browser_language();
} }
/** /**
...@@ -210,12 +219,14 @@ abstract class PLL_Choose_Lang { ...@@ -210,12 +219,14 @@ abstract class PLL_Choose_Lang {
* Polylang fallbacks to the default language * Polylang fallbacks to the default language
* *
* @since 1.0 * @since 1.0
* @since 2.7 Added $cookie parameter.
* *
* @param string $language preferred language code * @param string|bool $language Preferred language code, false if none has been found.
* @param bool $cookie Whether the preferred language has been defined by the cookie.
*/ */
$slug = apply_filters( 'pll_preferred_language', $this->options['browser'] ? $this->get_preferred_browser_language() : false ); $slug = apply_filters( 'pll_preferred_language', $language, $cookie );
// return default if there is no preferences in the browser or preferences does not match our languages or it is requested not to use the browser preference // Return default if there is no preferences in the browser or preferences does not match our languages or it is requested not to use the browser preference
return ( $lang = $this->model->get_language( $slug ) ) ? $lang : $this->model->get_language( $this->options['default_lang'] ); return ( $lang = $this->model->get_language( $slug ) ) ? $lang : $this->model->get_language( $this->options['default_lang'] );
} }
...@@ -274,6 +285,7 @@ abstract class PLL_Choose_Lang { ...@@ -274,6 +285,7 @@ abstract class PLL_Choose_Lang {
*/ */
if ( $redirect = apply_filters( 'pll_redirect_home', $redirect ) ) { if ( $redirect = apply_filters( 'pll_redirect_home', $redirect ) ) {
$this->maybe_setcookie(); $this->maybe_setcookie();
header( 'Vary: Accept-Language' );
wp_safe_redirect( $redirect, 302, POLYLANG ); wp_safe_redirect( $redirect, 302, POLYLANG );
exit; exit;
} }
......
...@@ -185,12 +185,12 @@ class PLL_Frontend_Auto_Translate { ...@@ -185,12 +185,12 @@ class PLL_Frontend_Auto_Translate {
// Array of post ids // Array of post ids
// post_parent__in & post_parent__not_in since WP 3.6 // post_parent__in & post_parent__not_in since WP 3.6
foreach ( array( 'post__in', 'post__not_in', 'post_parent__in', 'post_parent__not_in' ) as $key ) { foreach ( array( 'post__in', 'post__not_in', 'post_parent__in', 'post_parent__not_in' ) as $key ) { // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn
$arr = array(); $arr = array();
if ( ! empty( $qv[ $key ] ) ) { if ( ! empty( $qv[ $key ] ) ) {
// post__in used by the 2 functions below // post__in used by the 2 functions below
// Useless to filter them as output is already in the right language and would result in performance loss // Useless to filter them as output is already in the right language and would result in performance loss
foreach ( debug_backtrace() as $trace ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions foreach ( debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ) as $trace ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions
if ( in_array( $trace['function'], array( 'wp_nav_menu', 'gallery_shortcode' ) ) ) { if ( in_array( $trace['function'], array( 'wp_nav_menu', 'gallery_shortcode' ) ) ) {
return; return;
} }
...@@ -216,6 +216,8 @@ class PLL_Frontend_Auto_Translate { ...@@ -216,6 +216,8 @@ class PLL_Frontend_Auto_Translate {
*/ */
public function get_terms_args( $args, $taxonomies ) { public function get_terms_args( $args, $taxonomies ) {
if ( ! isset( $args['lang'] ) && ! empty( $args['include'] ) && ( empty( $taxonomies ) || $this->model->is_translated_taxonomy( $taxonomies ) ) ) { if ( ! isset( $args['lang'] ) && ! empty( $args['include'] ) && ( empty( $taxonomies ) || $this->model->is_translated_taxonomy( $taxonomies ) ) ) {
$arr = array();
foreach ( wp_parse_id_list( $args['include'] ) as $id ) { foreach ( wp_parse_id_list( $args['include'] ) as $id ) {
$arr[] = ( $tr = $this->get_term( $id ) ) ? $tr : $id; $arr[] = ( $tr = $this->get_term( $id ) ) ? $tr : $id;
} }
......
...@@ -175,6 +175,8 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links { ...@@ -175,6 +175,8 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
return; return;
} }
$urls = array();
// Google recommends to include self link https://support.google.com/webmasters/answer/189077?hl=en // Google recommends to include self link https://support.google.com/webmasters/answer/189077?hl=en
foreach ( $this->model->get_languages_list() as $language ) { foreach ( $this->model->get_languages_list() as $language ) {
if ( $url = $this->links->get_translation_url( $language ) ) { if ( $url = $this->links->get_translation_url( $language ) ) {
...@@ -184,6 +186,8 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links { ...@@ -184,6 +186,8 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
// Outputs the section only if there are translations ( $urls always contains self link ) // Outputs the section only if there are translations ( $urls always contains self link )
if ( ! empty( $urls ) && count( $urls ) > 1 ) { if ( ! empty( $urls ) && count( $urls ) > 1 ) {
$languages = array();
$hreflangs = array();
// Prepare the list of languages to remove the country code // Prepare the list of languages to remove the country code
foreach ( array_keys( $urls ) as $locale ) { foreach ( array_keys( $urls ) as $locale ) {
...@@ -285,7 +289,7 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links { ...@@ -285,7 +289,7 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
); );
} }
$traces = version_compare( PHP_VERSION, '5.2.5', '>=' ) ? debug_backtrace( false ) : debug_backtrace(); // phpcs:ignore WordPress.PHP.DevelopmentFunctions $traces = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
unset( $traces[0], $traces[1] ); // We don't need the last 2 calls: this function + call_user_func_array (or apply_filters on PHP7+) unset( $traces[0], $traces[1] ); // We don't need the last 2 calls: this function + call_user_func_array (or apply_filters on PHP7+)
foreach ( $traces as $trace ) { foreach ( $traces as $trace ) {
......
...@@ -55,7 +55,6 @@ class PLL_Frontend_Links extends PLL_Links { ...@@ -55,7 +55,6 @@ class PLL_Frontend_Links extends PLL_Links {
*/ */
if ( ! $url = apply_filters( 'pll_pre_translation_url', '', $language, $queried_object_id ) ) { if ( ! $url = apply_filters( 'pll_pre_translation_url', '', $language, $queried_object_id ) ) {
$qv = $wp_query->query_vars; $qv = $wp_query->query_vars;
$hide = $this->options['default_lang'] == $language->slug && $this->options['hide_default'];
// Post and attachment // Post and attachment
if ( is_single() && ( $this->options['media_support'] || ! is_attachment() ) && ( $id = $this->model->post->get( $queried_object_id, $language ) ) && $this->model->post->current_user_can_read( $id ) ) { if ( is_single() && ( $this->options['media_support'] || ! is_attachment() ) && ( $id = $this->model->post->get( $queried_object_id, $language ) ) && $this->model->post->current_user_can_read( $id ) ) {
...@@ -96,7 +95,7 @@ class PLL_Frontend_Links extends PLL_Links { ...@@ -96,7 +95,7 @@ class PLL_Frontend_Links extends PLL_Links {
$lang = $this->model->term->get_language( $term->term_id ); $lang = $this->model->term->get_language( $term->term_id );
if ( ! $lang || $language->slug == $lang->slug ) { if ( ! $lang || $language->slug == $lang->slug ) {
$url = wpcom_vip_get_term_link( $term, $term->taxonomy ); // Self link $url = get_term_link( $term, $term->taxonomy ); // Self link
} }
elseif ( $tr_id = $this->model->term->get_translation( $term->term_id, $language ) ) { elseif ( $tr_id = $this->model->term->get_translation( $term->term_id, $language ) ) {
...@@ -115,7 +114,7 @@ class PLL_Frontend_Links extends PLL_Links { ...@@ -115,7 +114,7 @@ class PLL_Frontend_Links extends PLL_Links {
* @param array $args Arguments used to evaluated the number of posts in the archive * @param array $args Arguments used to evaluated the number of posts in the archive
*/ */
if ( ! apply_filters( 'pll_hide_archive_translation_url', ! $count, $language->slug, array( 'taxonomy' => $term->taxonomy ) ) ) { if ( ! apply_filters( 'pll_hide_archive_translation_url', ! $count, $language->slug, array( 'taxonomy' => $term->taxonomy ) ) ) {
$url = wpcom_vip_get_term_link( $tr_term, $term->taxonomy ); $url = get_term_link( $tr_term, $term->taxonomy );
} }
} }
} }
......
...@@ -92,7 +92,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu { ...@@ -92,7 +92,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
$new_items = array(); $new_items = array();
$offset = 0; $offset = 0;
foreach ( $items as $key => $item ) { foreach ( $items as $item ) {
if ( $options = get_post_meta( $item->ID, '_pll_menu_item', true ) ) { if ( $options = get_post_meta( $item->ID, '_pll_menu_item', true ) ) {
$i = 0; $i = 0;
...@@ -219,7 +219,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu { ...@@ -219,7 +219,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
// First get multilingual menu locations from DB // First get multilingual menu locations from DB
$theme = get_option( 'stylesheet' ); $theme = get_option( 'stylesheet' );
foreach ( $menus as $loc => $menu ) { foreach ( array_keys( $menus ) as $loc ) {
$menus[ $loc ] = empty( $this->options['nav_menus'][ $theme ][ $loc ][ $this->curlang->slug ] ) ? 0 : $this->options['nav_menus'][ $theme ][ $loc ][ $this->curlang->slug ]; $menus[ $loc ] = empty( $this->options['nav_menus'][ $theme ][ $loc ][ $this->curlang->slug ] ) ? 0 : $this->options['nav_menus'][ $theme ][ $loc ][ $this->curlang->slug ];
} }
...@@ -275,7 +275,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu { ...@@ -275,7 +275,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
if ( ! $menu && ! $args['theme_location'] ) { if ( ! $menu && ! $args['theme_location'] ) {
$menus = wp_get_nav_menus(); $menus = wp_get_nav_menus();
foreach ( $menus as $menu_maybe ) { foreach ( $menus as $menu_maybe ) {
if ( $menu_items = wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) ) ) { if ( wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) ) ) {
foreach ( $this->options['nav_menus'][ $theme ] as $menus ) { foreach ( $this->options['nav_menus'][ $theme ] as $menus ) {
if ( in_array( $menu_maybe->term_id, $menus ) && ! empty( $menus[ $this->curlang->slug ] ) ) { if ( in_array( $menu_maybe->term_id, $menus ) && ! empty( $menus[ $this->curlang->slug ] ) ) {
$args['menu'] = $menus[ $this->curlang->slug ]; $args['menu'] = $menus[ $this->curlang->slug ];
......
...@@ -92,12 +92,14 @@ class PLL_Frontend extends PLL_Base { ...@@ -92,12 +92,14 @@ class PLL_Frontend extends PLL_Base {
// Share term slugs // Share term slugs
if ( $this->options['force_lang'] && class_exists( 'PLL_Share_Term_Slug' ) ) { if ( $this->options['force_lang'] && class_exists( 'PLL_Share_Term_Slug' ) ) {
$this->share_term_slug = version_compare( $GLOBALS['wp_version'], '4.8', '<' ) ? $this->share_term_slug = new PLL_Share_Term_Slug( $this );
new PLL_Frontend_Share_Term_Slug( $this ) :
new PLL_Share_Term_Slug( $this );
} }
} }
if ( class_exists( 'PLL_Sync_Post_Model' ) ) {
$this->sync_post_model = new PLL_Sync_Post_Model( $this );
}
if ( class_exists( 'PLL_Sync_Post' ) ) { if ( class_exists( 'PLL_Sync_Post' ) ) {
$this->sync_post = new PLL_Sync_Post( $this ); $this->sync_post = new PLL_Sync_Post( $this );
} }
......
...@@ -372,9 +372,9 @@ function pll_get_term_translations( $term_id ) { ...@@ -372,9 +372,9 @@ function pll_get_term_translations( $term_id ) {
* *
* @since 1.5 * @since 1.5
* *
* @param string $lang language code * @param string $lang Language code.
* @param array $args ( accepted keys: post_type, m, year, monthnum, day, author, author_name, post_format ) * @param array $args WP_Query arguments ( accepted keys: post_type, m, year, monthnum, day, author, author_name, post_format, post_status ).
* @return int posts count * @return int Posts count.
*/ */
function pll_count_posts( $lang, $args = array() ) { function pll_count_posts( $lang, $args = array() ) {
return PLL()->model->count_posts( PLL()->model->get_language( $lang ), $args ); return PLL()->model->count_posts( PLL()->model->get_language( $lang ), $args );
......
...@@ -139,7 +139,7 @@ abstract class PLL_Base { ...@@ -139,7 +139,7 @@ abstract class PLL_Base {
foreach ( $this as $prop => &$obj ) { foreach ( $this as $prop => &$obj ) {
if ( is_object( $obj ) && method_exists( $obj, $func ) ) { if ( is_object( $obj ) && method_exists( $obj, $func ) ) {
if ( WP_DEBUG ) { if ( WP_DEBUG ) {
$debug = debug_backtrace(); // phpcs:ignore WordPress.PHP.DevelopmentFunctions $debug = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
$i = 1 + empty( $debug[1]['line'] ); // The file and line are in $debug[2] if the function was called using call_user_func $i = 1 + empty( $debug[1]['line'] ); // The file and line are in $debug[2] if the function was called using call_user_func
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions
sprintf( sprintf(
...@@ -155,7 +155,7 @@ abstract class PLL_Base { ...@@ -155,7 +155,7 @@ abstract class PLL_Base {
} }
} }
$debug = debug_backtrace(); // phpcs:ignore WordPress.PHP.DevelopmentFunctions $debug = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions
sprintf( sprintf(
'Call to undefined function PLL()->%1$s() in %2$s on line %3$s' . "\nError handler", 'Call to undefined function PLL()->%1$s() in %2$s on line %3$s' . "\nError handler",
......
...@@ -30,6 +30,9 @@ class Polylang { ...@@ -30,6 +30,9 @@ class Polylang {
require_once PLL_INC . '/functions.php'; // VIP functions require_once PLL_INC . '/functions.php'; // VIP functions
spl_autoload_register( array( $this, 'autoload' ) ); // Autoload classes spl_autoload_register( array( $this, 'autoload' ) ); // Autoload classes
// register an action when plugin is activating.
register_activation_hook( POLYLANG_BASENAME, array( 'PLL_Wizard', 'start_wizard' ) );
$install = new PLL_Install( POLYLANG_BASENAME ); $install = new PLL_Install( POLYLANG_BASENAME );
// Stopping here if we are going to deactivate the plugin ( avoids breaking rewrite rules ) // Stopping here if we are going to deactivate the plugin ( avoids breaking rewrite rules )
...@@ -98,7 +101,7 @@ class Polylang { ...@@ -98,7 +101,7 @@ class Polylang {
foreach ( $dirs as $dir ) { foreach ( $dirs as $dir ) {
if ( file_exists( $file = "$dir/$class.php" ) ) { if ( file_exists( $file = "$dir/$class.php" ) ) {
require_once $file; require_once $file; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable
return; return;
} }
} }
...@@ -155,6 +158,17 @@ class Polylang { ...@@ -155,6 +158,17 @@ class Polylang {
return 0 === strpos( $req_uri, rest_get_url_prefix() . '/' ) || ! empty( $rest_route ); return 0 === strpos( $req_uri, rest_get_url_prefix() . '/' ) || ! empty( $rest_route );
} }
/**
* Tells if we are in the wizard process.
*
* @since 2.7
*
* @return bool
*/
public static function is_wizard() {
return isset( $_GET['page'] ) && ! empty( $_GET['page'] ) && 'mlang_wizard' === sanitize_key( $_GET['page'] ); // phpcs:ignore WordPress.Security.NonceVerification
}
/** /**
* Defines constants * Defines constants
* May be overridden by a plugin if set before plugins_loaded, 1 * May be overridden by a plugin if set before plugins_loaded, 1
...@@ -177,9 +191,9 @@ class Polylang { ...@@ -177,9 +191,9 @@ class Polylang {
define( 'PLL_ADMIN', wp_doing_cron() || ( defined( 'WP_CLI' ) && WP_CLI ) || ( is_admin() && ! PLL_AJAX_ON_FRONT ) ); define( 'PLL_ADMIN', wp_doing_cron() || ( defined( 'WP_CLI' ) && WP_CLI ) || ( is_admin() && ! PLL_AJAX_ON_FRONT ) );
} }
// Settings page whatever the tab // Settings page whatever the tab except for the wizard which needs to be an admin process.
if ( ! defined( 'PLL_SETTINGS' ) ) { if ( ! defined( 'PLL_SETTINGS' ) ) {
define( 'PLL_SETTINGS', is_admin() && ( ( isset( $_GET['page'] ) && 0 === strpos( sanitize_key( $_GET['page'] ), 'mlang' ) ) || ! empty( $_REQUEST['pll_ajax_settings'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification define( 'PLL_SETTINGS', is_admin() && ( ( isset( $_GET['page'] ) && 0 === strpos( sanitize_key( $_GET['page'] ), 'mlang' ) && ! self::is_wizard() ) || ! empty( $_REQUEST['pll_ajax_settings'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification
} }
} }
...@@ -219,7 +233,7 @@ class Polylang { ...@@ -219,7 +233,7 @@ class Polylang {
* *
* @param string $class either PLL_Model or PLL_Admin_Model * @param string $class either PLL_Model or PLL_Admin_Model
*/ */
$class = apply_filters( 'pll_model', PLL_SETTINGS ? 'PLL_Admin_Model' : 'PLL_Model' ); $class = apply_filters( 'pll_model', PLL_SETTINGS || self::is_wizard() ? 'PLL_Admin_Model' : 'PLL_Model' );
$model = new $class( $options ); $model = new $class( $options );
$links_model = $model->get_links_model(); $links_model = $model->get_links_model();
......
...@@ -227,7 +227,7 @@ class PLL_CRUD_Posts { ...@@ -227,7 +227,7 @@ class PLL_CRUD_Posts {
if ( ! empty( $ids ) ) { if ( ! empty( $ids ) ) {
// Regenerate intermediate sizes if it's an image ( since we could not prevent WP deleting them before ). // Regenerate intermediate sizes if it's an image ( since we could not prevent WP deleting them before ).
require_once ABSPATH . 'wp-admin/includes/image.php'; // In case the file is deleted outside admin. require_once ABSPATH . 'wp-admin/includes/image.php'; // In case the file is deleted outside admin.
wp_update_attachment_metadata( $ids[0], wp_generate_attachment_metadata( $ids[0], $file ) ); wp_update_attachment_metadata( $ids[0], wp_slash( wp_generate_attachment_metadata( $ids[0], $file ) ) ); // Directly uses update_post_meta, so expects slashed.
return ''; // Prevent deleting the main file. return ''; // Prevent deleting the main file.
} }
...@@ -239,9 +239,9 @@ class PLL_CRUD_Posts { ...@@ -239,9 +239,9 @@ class PLL_CRUD_Posts {
* *
* @since 1.8 * @since 1.8
* *
* @param int $post_id * @param int $post_id Original attachment id.
* @param string|object $lang * @param string|object $lang New translation language.
* @return int id of the translated media * @return int Attachment id of the translated media.
*/ */
public function create_media_translation( $post_id, $lang ) { public function create_media_translation( $post_id, $lang ) {
if ( empty( $post_id ) ) { if ( empty( $post_id ) ) {
...@@ -254,30 +254,34 @@ class PLL_CRUD_Posts { ...@@ -254,30 +254,34 @@ class PLL_CRUD_Posts {
return $post; return $post;
} }
$lang = $this->model->get_language( $lang ); // Make sure we get a valid language slug $lang = $this->model->get_language( $lang ); // Make sure we get a valid language slug.
// Create a new attachment ( translate attachment parent if exists ) // Create a new attachment ( translate attachment parent if exists ).
add_filter( 'pll_enable_duplicate_media', '__return_false', 99 ); // Avoid a conflict with automatic duplicate at upload add_filter( 'pll_enable_duplicate_media', '__return_false', 99 ); // Avoid a conflict with automatic duplicate at upload.
$post->ID = null; // Will force the creation $post->ID = null; // Will force the creation
$post->post_parent = ( $post->post_parent && $tr_parent = $this->model->post->get_translation( $post->post_parent, $lang->slug ) ) ? $tr_parent : 0; $post->post_parent = ( $post->post_parent && $tr_parent = $this->model->post->get_translation( $post->post_parent, $lang->slug ) ) ? $tr_parent : 0;
$post->tax_input = array( 'language' => array( $lang->slug ) ); // Assigns the language $post->tax_input = array( 'language' => array( $lang->slug ) ); // Assigns the language.
$tr_id = wp_insert_attachment( wp_slash( (array) $post ) ); $tr_id = wp_insert_attachment( wp_slash( (array) $post ) );
remove_filter( 'pll_enable_duplicate_media', '__return_false', 99 ); // Restore automatic duplicate at upload remove_filter( 'pll_enable_duplicate_media', '__return_false', 99 ); // Restore automatic duplicate at upload.
// Copy metadata, attached file and alternative text // Copy metadata.
foreach ( array( '_wp_attachment_metadata', '_wp_attached_file', '_wp_attachment_image_alt' ) as $key ) { if ( $data = wp_get_attachment_metadata( $post_id, true ) ) { // Unfiltered.
if ( $meta = get_post_meta( $post_id, $key, true ) ) { wp_update_attachment_metadata( $tr_id, wp_slash( $data ) ); // Directly uses update_post_meta, so expects slashed.
add_post_meta( $tr_id, $key, wp_slash( $meta ) );
}
} }
$this->model->post->set_language( $tr_id, $lang ); // Copy attached file.
if ( $file = get_attached_file( $post_id, true ) ) { // Unfiltered.
update_attached_file( $tr_id, wp_slash( $file ) ); // Directly uses update_post_meta, so expects slashed.
}
$translations = $this->model->post->get_translations( $post_id ); // Copy alternative text. Direct use of the meta as there is no filtered wrapper to manipulate it.
if ( ! $translations && $src_lang = $this->model->post->get_language( $post_id ) ) { if ( $text = get_post_meta( $post_id, '_wp_attachment_image_alt', true ) ) {
$translations[ $src_lang->slug ] = $post_id; add_post_meta( $tr_id, '_wp_attachment_image_alt', wp_slash( $text ) );
} }
$this->model->post->set_language( $tr_id, $lang );
$translations = $this->model->post->get_translations( $post_id );
$translations[ $lang->slug ] = $tr_id; $translations[ $lang->slug ] = $tr_id;
$this->model->post->save_translations( $tr_id, $translations ); $this->model->post->save_translations( $tr_id, $translations );
...@@ -286,9 +290,9 @@ class PLL_CRUD_Posts { ...@@ -286,9 +290,9 @@ class PLL_CRUD_Posts {
* *
* @since 1.6.4 * @since 1.6.4
* *
* @param int $post_id post id of the source media * @param int $post_id Post id of the source media.
* @param int $tr_id post id of the new media translation * @param int $tr_id Post id of the new media translation.
* @param string $slug language code of the new translation * @param string $slug Language code of the new translation.
*/ */
do_action( 'pll_translate_media', $post_id, $tr_id, $lang->slug ); do_action( 'pll_translate_media', $post_id, $tr_id, $lang->slug );
return $tr_id; return $tr_id;
......
...@@ -335,9 +335,9 @@ class PLL_Filters { ...@@ -335,9 +335,9 @@ class PLL_Filters {
* @return array Personal data * @return array Personal data
*/ */
public function user_data_exporter( $email_address ) { public function user_data_exporter( $email_address ) {
$email_address = trim( $email_address ); $email_address = trim( $email_address );
$data_to_export = array();
$data_to_export = array(); $user_data_to_export = array();
if ( $user = get_user_by( 'email', $email_address ) ) { if ( $user = get_user_by( 'email', $email_address ) ) {
foreach ( $this->model->get_languages_list() as $lang ) { foreach ( $this->model->get_languages_list() as $lang ) {
......
...@@ -18,54 +18,7 @@ if ( ! function_exists( 'wpcom_vip_get_page_by_title' ) ) { ...@@ -18,54 +18,7 @@ if ( ! function_exists( 'wpcom_vip_get_page_by_title' ) ) {
* @return WP_Post|array|null WP_Post (or array) on success, or null on failure. * @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
*/ */
function wpcom_vip_get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) { function wpcom_vip_get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) {
return get_page_by_title( $page_title, $output, $post_type ); return get_page_by_title( $page_title, $output, $post_type ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.get_page_by_title_get_page_by_title
}
}
if ( ! function_exists( 'wpcom_vip_get_category_by_slug' ) ) {
/**
* Retrieve category object by category slug.
*
* @since 2.0
*
* @param string $slug The category slug.
* @return object Category data object
*/
function wpcom_vip_get_category_by_slug( $slug ) {
return get_category_by_slug( $slug );
}
}
if ( ! function_exists( 'wpcom_vip_get_term_by' ) ) {
/**
* Get all Term data from database by Term field and data.
*
* @since 2.0
*
* @param string $field Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id'
* @param string|int $value Search for this term value
* @param string $taxonomy Taxonomy name. Optional, if `$field` is 'term_taxonomy_id'.
* @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N. Default OBJECT.
* @param string $filter Optional, default is raw or no WordPress defined filter will applied.
* @return WP_Term|array|false WP_Term instance (or array) on success. Will return false if `$taxonomy` does not exist or `$term` was not found.
*/
function wpcom_vip_get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
return get_term_by( $field, $value, $taxonomy, $output, $filter );
}
}
if ( ! function_exists( 'wpcom_vip_get_term_link' ) ) {
/**
* Generate a permalink for a taxonomy term archive.
*
* @since 2.0
*
* @param object|int|string $term The term object, ID, or slug whose link will be retrieved.
* @param string $taxonomy Optional. Taxonomy. Default empty.
* @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist.
*/
function wpcom_vip_get_term_link( $term, $taxonomy = '' ) {
return get_term_link( $term, $taxonomy );
} }
} }
......
...@@ -102,7 +102,7 @@ class PLL_Language { ...@@ -102,7 +102,7 @@ class PLL_Language {
* @return array Flag informations. * @return array Flag informations.
*/ */
public static function get_flag_informations( $code ) { public static function get_flag_informations( $code ) {
$flag['url'] = ''; $flag = array( 'url' => '' );
// Polylang builtin flags // Polylang builtin flags
if ( ! empty( $code ) && file_exists( POLYLANG_DIR . ( $file = '/flags/' . $code . '.png' ) ) ) { if ( ! empty( $code ) && file_exists( POLYLANG_DIR . ( $file = '/flags/' . $code . '.png' ) ) ) {
...@@ -145,7 +145,7 @@ class PLL_Language { ...@@ -145,7 +145,7 @@ class PLL_Language {
* @since 1.2 * @since 1.2
*/ */
public function set_flag() { public function set_flag() {
$flags['flag'] = self::get_flag_informations( $this->flag_code ); $flags = array( 'flag' => self::get_flag_informations( $this->flag_code ) );
// Custom flags ? // Custom flags ?
$directories = array( $directories = array(
...@@ -210,19 +210,32 @@ class PLL_Language { ...@@ -210,19 +210,32 @@ class PLL_Language {
*/ */
$this->{$key} = apply_filters( $this->{$key} = apply_filters(
'pll_get_flag', 'pll_get_flag',
empty( $flag['src'] ) ? '' : sprintf( self::get_flag_html( $flag, $title, $this->name ),
'<img src="%s" title="%s" alt="%s"%s%s />',
$flag['src'],
esc_attr( $title ),
esc_attr( $this->name ),
empty( $flag['width'] ) ? '' : sprintf( ' width="%s"', (int) $flag['width'] ),
empty( $flag['height'] ) ? '' : sprintf( ' height="%s"', (int) $flag['height'] )
),
$this->slug $this->slug
); );
} }
} }
/**
* Get HTML code for flag
*
* @since 2.7
*
* @param array $flag flag properties: src, width and height
* @param string $title optional title attribute
* @param string $alt optional alt attribute
*/
public static function get_flag_html( $flag, $title = '', $alt = '' ) {
return empty( $flag['src'] ) ? '' : sprintf(
'<img src="%s"%s%s%s%s />',
$flag['src'],
empty( $title ) ? '' : sprintf( ' title="%s"', esc_attr( $title ) ),
empty( $alt ) ? '' : sprintf( ' alt="%s"', esc_attr( $alt ) ),
empty( $flag['width'] ) ? '' : sprintf( ' width="%s"', (int) $flag['width'] ),
empty( $flag['height'] ) ? '' : sprintf( ' height="%s"', (int) $flag['height'] )
);
}
/** /**
* Replace flag by custom flag * Replace flag by custom flag
* Takes care of url scheme * Takes care of url scheme
......
...@@ -153,7 +153,7 @@ class PLL_License { ...@@ -153,7 +153,7 @@ class PLL_License {
$response = wp_remote_post( $response = wp_remote_post(
$this->api_url, $this->api_url,
array( array(
'timeout' => 15, 'timeout' => 3,
'sslverify' => false, 'sslverify' => false,
'body' => $api_params, 'body' => $api_params,
) )
...@@ -175,4 +175,122 @@ class PLL_License { ...@@ -175,4 +175,122 @@ class PLL_License {
update_option( 'polylang_licenses', $licenses ); // FIXME called multiple times when saving all licenses update_option( 'polylang_licenses', $licenses ); // FIXME called multiple times when saving all licenses
} }
/**
* Get the html form field in a table row (one per license key) for display
*
* @since 2.7
*
* @return string
*/
public function get_form_field() {
if ( ! empty( $this->license_data ) ) {
$license = $this->license_data;
}
$class = 'license-null';
$out = sprintf(
'<td><label for="pll-licenses[%1$s]">%2$s</label></td>' .
'<td><input name="licenses[%1$s]" id="pll-licenses[%1$s]" type="text" value="%3$s" class="regular-text code" />',
esc_attr( $this->id ),
esc_attr( $this->name ),
esc_html( $this->license_key )
);
if ( ! empty( $license ) && is_object( $license ) ) {
$now = time();
$expiration = isset( $license->expires ) ? strtotime( $license->expires ) : false;
// Special case: the license expired after the last check
if ( $license->success && $expiration && $expiration < $now ) {
$license->success = false;
$license->error = 'expired';
}
if ( false === $license->success ) {
$class = 'notice-error notice-alt';
switch ( $license->error ) {
case 'expired':
$message = sprintf(
/* translators: %1$s is a date, %2$s is link start tag, %3$s is link end tag. */
esc_html__( 'Your license key expired on %1$s. Please %2$srenew your license key%3$s.', 'polylang' ),
esc_html( date_i18n( get_option( 'date_format' ), $expiration ) ),
sprintf( '<a href="%s" target="_blank">', esc_url( 'https://polylang.pro/checkout/?edd_license_key=' . $this->license_key ) ),
'</a>'
);
break;
case 'disabled':
case 'revoked':
$message = esc_html__( 'Your license key has been disabled.', 'polylang' );
break;
case 'missing':
$message = sprintf(
/* translators: %1$s is link start tag, %2$s is link end tag. */
esc_html__( 'Invalid license. Please %1$svisit your account page%2$s and verify it.', 'polylang' ),
sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account' ),
'</a>'
);
break;
case 'invalid':
case 'site_inactive':
$message = sprintf(
/* translators: %1$s is a product name, %2$s is link start tag, %3$s is link end tag. */
esc_html__( 'Your %1$s license key is not active for this URL. Please %2$svisit your account page%3$s to manage your license key URLs.', 'polylang' ),
esc_html( $this->name ),
sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account' ),
'</a>'
);
break;
case 'item_name_mismatch':
/* translators: %s is a product name */
$message = sprintf( esc_html__( 'This is not a %s license key.', 'polylang' ), esc_html( $this->name ) );
break;
case 'no_activations_left':
$message = sprintf(
/* translators: %1$s is link start tag, %2$s is link end tag */
esc_html__( 'Your license key has reached its activation limit. %1$sView possible upgrades%2$s now.', 'polylang' ),
sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account' ),
'</a>'
);
break;
}
} else {
$class = 'license-valid';
$out .= sprintf( '<button id="deactivate_%s" type="button" class="button button-secondary pll-deactivate-license">%s</button>', esc_attr( $this->id ), esc_html__( 'Deactivate', 'polylang' ) );
if ( 'lifetime' === $license->expires ) {
$message = esc_html__( 'The license key never expires.', 'polylang' );
} elseif ( $expiration > $now && $expiration - $now < ( DAY_IN_SECONDS * 30 ) ) {
$class = 'notice-warning notice-alt';
$message = sprintf(
/* translators: %1$s is a date, %2$s is link start tag, %3$s is link end tag. */
esc_html__( 'Your license key will expire soon! Precisely, it will expire on %1$s. %2$sRenew your license key today!%3$s.', 'polylang' ),
esc_html( date_i18n( get_option( 'date_format' ), $expiration ) ),
sprintf( '<a href="%s" target="_blank">', esc_url( 'https://polylang.pro/checkout/?edd_license_key=' . $this->license_key ) ),
'</a>'
);
} else {
$message = sprintf(
/* translators: %s is a date */
esc_html__( 'Your license key expires on %s.', 'polylang' ),
esc_html( date_i18n( get_option( 'date_format' ), $expiration ) )
);
}
}
}
if ( ! empty( $message ) ) {
$out .= '<p>' . $message . '</p>';
}
return sprintf( '<tr id="pll-license-%s" class="%s">%s</tr>', esc_attr( $this->id ), $class, $out );
}
} }
...@@ -59,10 +59,10 @@ class PLL_Links_Directory extends PLL_Links_Permalinks { ...@@ -59,10 +59,10 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
if ( ! empty( $lang ) ) { if ( ! empty( $lang ) ) {
$base = $this->options['rewrite'] ? '' : 'language/'; $base = $this->options['rewrite'] ? '' : 'language/';
$slug = $this->options['default_lang'] == $lang->slug && $this->options['hide_default'] ? '' : $base . $lang->slug . '/'; $slug = $this->options['default_lang'] == $lang->slug && $this->options['hide_default'] ? '' : $base . $lang->slug . '/';
$root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : preg_replace( '/^https?:\/\//', '://', $this->home . '/' . $this->root ); $root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : preg_replace( '#^https?://#', '://', $this->home . '/' . $this->root );
if ( false === strpos( $url, $new = $root . $slug ) ) { if ( false === strpos( $url, $new = $root . $slug ) ) {
$pattern = str_replace( '/', '\/', $root ); $pattern = preg_quote( $root, '#' );
$pattern = '#' . $pattern . '#'; $pattern = '#' . $pattern . '#';
return preg_replace( $pattern, $new, $url, 1 ); // Only once return preg_replace( $pattern, $new, $url, 1 ); // Only once
} }
...@@ -80,6 +80,8 @@ class PLL_Links_Directory extends PLL_Links_Permalinks { ...@@ -80,6 +80,8 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
* @return string modified url * @return string modified url
*/ */
public function remove_language_from_link( $url ) { public function remove_language_from_link( $url ) {
$languages = array();
foreach ( $this->model->get_languages_list() as $language ) { foreach ( $this->model->get_languages_list() as $language ) {
if ( ! $this->options['hide_default'] || $this->options['default_lang'] != $language->slug ) { if ( ! $this->options['hide_default'] || $this->options['default_lang'] != $language->slug ) {
$languages[] = $language->slug; $languages[] = $language->slug;
...@@ -87,10 +89,10 @@ class PLL_Links_Directory extends PLL_Links_Permalinks { ...@@ -87,10 +89,10 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
} }
if ( ! empty( $languages ) ) { if ( ! empty( $languages ) ) {
$root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : preg_replace( '/^https?:\/\//', '://', $this->home . '/' . $this->root ); $root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : preg_replace( '#^https?://#', '://', $this->home . '/' . $this->root );
$pattern = str_replace( '/', '\/', $root ); $pattern = preg_quote( $root, '#' );
$pattern = '#' . $pattern . ( $this->options['rewrite'] ? '' : 'language\/' ) . '(' . implode( '|', $languages ) . ')(\/|$)#'; $pattern = '#' . $pattern . ( $this->options['rewrite'] ? '' : 'language/' ) . '(' . implode( '|', $languages ) . ')(/|$)#';
$url = preg_replace( $pattern, $root, $url ); $url = preg_replace( $pattern, $root, $url );
} }
return $url; return $url;
...@@ -115,8 +117,8 @@ class PLL_Links_Directory extends PLL_Links_Permalinks { ...@@ -115,8 +117,8 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
$root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : $this->home . '/' . $this->root; $root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : $this->home . '/' . $this->root;
$pattern = wp_parse_url( $root . ( $this->options['rewrite'] ? '' : 'language/' ), PHP_URL_PATH ); $pattern = wp_parse_url( $root . ( $this->options['rewrite'] ? '' : 'language/' ), PHP_URL_PATH );
$pattern = str_replace( '/', '\/', $pattern ); $pattern = preg_quote( $pattern, '#' );
$pattern = '#^' . $pattern . '(' . implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')(\/|$)#'; $pattern = '#^' . $pattern . '(' . implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')(/|$)#';
return preg_match( $pattern, trailingslashit( $path ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language return preg_match( $pattern, trailingslashit( $path ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
} }
......
...@@ -38,7 +38,7 @@ class PLL_Links_Domain extends PLL_Links_Abstract_Domain { ...@@ -38,7 +38,7 @@ class PLL_Links_Domain extends PLL_Links_Abstract_Domain {
*/ */
public function add_language_to_link( $url, $lang ) { public function add_language_to_link( $url, $lang ) {
if ( ! empty( $lang ) && ! empty( $this->hosts[ $lang->slug ] ) ) { if ( ! empty( $lang ) && ! empty( $this->hosts[ $lang->slug ] ) ) {
$url = preg_replace( '#:\/\/(' . wp_parse_url( $this->home, PHP_URL_HOST ) . ')($|\/.*)#', '://' . $this->hosts[ $lang->slug ] . '$2', $url ); $url = preg_replace( '#://(' . wp_parse_url( $this->home, PHP_URL_HOST ) . ')($|/.*)#', '://' . $this->hosts[ $lang->slug ] . '$2', $url );
} }
return $url; return $url;
} }
...@@ -54,7 +54,7 @@ class PLL_Links_Domain extends PLL_Links_Abstract_Domain { ...@@ -54,7 +54,7 @@ class PLL_Links_Domain extends PLL_Links_Abstract_Domain {
*/ */
public function remove_language_from_link( $url ) { public function remove_language_from_link( $url ) {
if ( ! empty( $this->hosts ) ) { if ( ! empty( $this->hosts ) ) {
$url = preg_replace( '#:\/\/(' . implode( '|', $this->hosts ) . ')($|\/.*)#', '://' . wp_parse_url( $this->home, PHP_URL_HOST ) . '$2', $url ); $url = preg_replace( '#://(' . implode( '|', $this->hosts ) . ')($|/.*)#', '://' . wp_parse_url( $this->home, PHP_URL_HOST ) . '$2', $url );
} }
return $url; return $url;
} }
......
...@@ -44,7 +44,7 @@ abstract class PLL_Links_Permalinks extends PLL_Links_Model { ...@@ -44,7 +44,7 @@ abstract class PLL_Links_Permalinks extends PLL_Links_Model {
* @param string $modified_url The link to the first page * @param string $modified_url The link to the first page
* @param string $original_url The link to the original paged page * @param string $original_url The link to the original paged page
*/ */
return apply_filters( 'pll_remove_paged_from_link', preg_replace( '#\/page\/[0-9]+\/?#', $this->use_trailing_slashes ? '/' : '', $url ), $url ); return apply_filters( 'pll_remove_paged_from_link', preg_replace( '#/page/[0-9]+/?#', $this->use_trailing_slashes ? '/' : '', $url ), $url );
} }
/** /**
......
...@@ -49,6 +49,8 @@ class PLL_Links_Subdomain extends PLL_Links_Abstract_Domain { ...@@ -49,6 +49,8 @@ class PLL_Links_Subdomain extends PLL_Links_Abstract_Domain {
* @return string modified url * @return string modified url
*/ */
public function remove_language_from_link( $url ) { public function remove_language_from_link( $url ) {
$languages = array();
foreach ( $this->model->get_languages_list() as $language ) { foreach ( $this->model->get_languages_list() as $language ) {
if ( ! $this->options['hide_default'] || $this->options['default_lang'] != $language->slug ) { if ( ! $this->options['hide_default'] || $this->options['default_lang'] != $language->slug ) {
$languages[] = $language->slug; $languages[] = $language->slug;
...@@ -56,7 +58,7 @@ class PLL_Links_Subdomain extends PLL_Links_Abstract_Domain { ...@@ -56,7 +58,7 @@ class PLL_Links_Subdomain extends PLL_Links_Abstract_Domain {
} }
if ( ! empty( $languages ) ) { if ( ! empty( $languages ) ) {
$url = preg_replace( '#:\/\/(' . implode( '|', $languages ) . ')\.#', $this->www, $url ); $url = preg_replace( '#://(' . implode( '|', $languages ) . ')\.#', $this->www, $url );
} }
return $url; return $url;
......
...@@ -182,6 +182,7 @@ class PLL_Model { ...@@ -182,6 +182,7 @@ class PLL_Model {
$this->cache->set( 'language:' . $lang->tl_term_id, $lang ); $this->cache->set( 'language:' . $lang->tl_term_id, $lang );
$this->cache->set( 'language:' . $lang->slug, $lang ); $this->cache->set( 'language:' . $lang->slug, $lang );
$this->cache->set( 'language:' . $lang->locale, $lang ); $this->cache->set( 'language:' . $lang->locale, $lang );
$this->cache->set( 'language:' . $lang->w3c, $lang );
} }
$return = $this->cache->get( 'language:' . $value ); $return = $this->cache->get( 'language:' . $value );
} }
...@@ -427,6 +428,7 @@ class PLL_Model { ...@@ -427,6 +428,7 @@ class PLL_Model {
global $wpdb; global $wpdb;
$term_name = trim( wp_unslash( $term_name ) ); $term_name = trim( wp_unslash( $term_name ) );
$term_name = _wp_specialchars( $term_name );
$select = "SELECT t.term_id FROM $wpdb->terms AS t"; $select = "SELECT t.term_id FROM $wpdb->terms AS t";
$join = " INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id"; $join = " INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id";
...@@ -448,13 +450,13 @@ class PLL_Model { ...@@ -448,13 +450,13 @@ class PLL_Model {
* @since 1.2 * @since 1.2
* *
* @param object $lang PLL_Language instance. * @param object $lang PLL_Language instance.
* @param array $q WP_Query arguments ( accepted: post_type, m, year, monthnum, day, author, author_name, post_format ). * @param array $q WP_Query arguments ( accepted: post_type, m, year, monthnum, day, author, author_name, post_format, post_status ).
* @return int * @return int
*/ */
public function count_posts( $lang, $q = array() ) { public function count_posts( $lang, $q = array() ) {
global $wpdb; global $wpdb;
$q = wp_parse_args( $q, array( 'post_type' => 'post' ) ); $q = wp_parse_args( $q, array( 'post_type' => 'post', 'post_status' => 'publish' ) );
if ( ! is_array( $q['post_type'] ) ) { if ( ! is_array( $q['post_type'] ) ) {
$q['post_type'] = array( $q['post_type'] ); $q['post_type'] = array( $q['post_type'] );
...@@ -476,7 +478,7 @@ class PLL_Model { ...@@ -476,7 +478,7 @@ class PLL_Model {
if ( false === $counts ) { if ( false === $counts ) {
$select = "SELECT pll_tr.term_taxonomy_id, COUNT( * ) AS num_posts FROM {$wpdb->posts}"; $select = "SELECT pll_tr.term_taxonomy_id, COUNT( * ) AS num_posts FROM {$wpdb->posts}";
$join = $this->post->join_clause(); $join = $this->post->join_clause();
$where = " WHERE post_status = 'publish'"; $where = sprintf( " WHERE post_status = '%s'", esc_sql( $q['post_status'] ) );
$where .= sprintf( " AND {$wpdb->posts}.post_type IN ( '%s' )", join( "', '", esc_sql( $q['post_type'] ) ) ); $where .= sprintf( " AND {$wpdb->posts}.post_type IN ( '%s' )", join( "', '", esc_sql( $q['post_type'] ) ) );
$where .= $this->post->where_clause( $this->get_languages_list() ); $where .= $this->post->where_clause( $this->get_languages_list() );
$groupby = ' GROUP BY pll_tr.term_taxonomy_id'; $groupby = ' GROUP BY pll_tr.term_taxonomy_id';
...@@ -610,7 +612,7 @@ class PLL_Model { ...@@ -610,7 +612,7 @@ class PLL_Model {
if ( ! empty( $o ) && is_object( $this->$o ) && method_exists( $this->$o, $f ) ) { if ( ! empty( $o ) && is_object( $this->$o ) && method_exists( $this->$o, $f ) ) {
if ( WP_DEBUG ) { if ( WP_DEBUG ) {
$debug = debug_backtrace(); // phpcs:ignore WordPress.PHP.DevelopmentFunctions $debug = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
$i = 1 + empty( $debug[1]['line'] ); // the file and line are in $debug[2] if the function was called using call_user_func $i = 1 + empty( $debug[1]['line'] ); // the file and line are in $debug[2] if the function was called using call_user_func
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions
...@@ -627,7 +629,7 @@ class PLL_Model { ...@@ -627,7 +629,7 @@ class PLL_Model {
return call_user_func_array( array( $this->$o, $f ), $args ); return call_user_func_array( array( $this->$o, $f ), $args );
} }
$debug = debug_backtrace(); // phpcs:ignore WordPress.PHP.DevelopmentFunctions $debug = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions
sprintf( sprintf(
'Call to undefined function PLL()->model->%1$s() in %2$s on line %3$s' . "\nError handler", 'Call to undefined function PLL()->model->%1$s() in %2$s on line %3$s' . "\nError handler",
......
...@@ -57,6 +57,8 @@ class PLL_Nav_Menu { ...@@ -57,6 +57,8 @@ class PLL_Nav_Menu {
static $once; static $once;
global $_wp_registered_nav_menus; global $_wp_registered_nav_menus;
$arr = array();
if ( isset( $_wp_registered_nav_menus ) && ! $once ) { if ( isset( $_wp_registered_nav_menus ) && ! $once ) {
foreach ( $_wp_registered_nav_menus as $loc => $name ) { foreach ( $_wp_registered_nav_menus as $loc => $name ) {
foreach ( $this->model->get_languages_list() as $lang ) { foreach ( $this->model->get_languages_list() as $lang ) {
......
...@@ -51,9 +51,7 @@ class PLL_REST_Request extends PLL_Base { ...@@ -51,9 +51,7 @@ class PLL_REST_Request extends PLL_Base {
// Share term slugs // Share term slugs
if ( get_option( 'permalink_structure' ) && $this->options['force_lang'] && class_exists( 'PLL_Share_Term_Slug' ) ) { if ( get_option( 'permalink_structure' ) && $this->options['force_lang'] && class_exists( 'PLL_Share_Term_Slug' ) ) {
$this->share_term_slug = version_compare( $GLOBALS['wp_version'], '4.8', '<' ) ? $this->share_term_slug = new PLL_Share_Term_Slug( $this );
new PLL_Frontend_Share_Term_Slug( $this ) :
new PLL_Share_Term_Slug( $this );
} }
// Translate slugs, only for pretty permalinks // Translate slugs, only for pretty permalinks
...@@ -63,6 +61,10 @@ class PLL_REST_Request extends PLL_Base { ...@@ -63,6 +61,10 @@ class PLL_REST_Request extends PLL_Base {
$this->translate_slugs = new PLL_Translate_Slugs( $slugs_model, $curlang ); $this->translate_slugs = new PLL_Translate_Slugs( $slugs_model, $curlang );
} }
if ( class_exists( 'PLL_Sync_Post_Model' ) ) {
$this->sync_post_model = new PLL_Sync_Post_Model( $this );
}
if ( class_exists( 'PLL_Sync_Post_REST' ) ) { if ( class_exists( 'PLL_Sync_Post_REST' ) ) {
$this->sync_post = new PLL_Sync_Post_REST( $this ); $this->sync_post = new PLL_Sync_Post_REST( $this );
} }
......
...@@ -42,8 +42,8 @@ class PLL_Switcher { ...@@ -42,8 +42,8 @@ class PLL_Switcher {
* @return array * @return array
*/ */
protected function get_elements( $links, $args ) { protected function get_elements( $links, $args ) {
$first = true; $first = true;
$out = array();
foreach ( $links->model->get_languages_list( array( 'hide_empty' => $args['hide_if_empty'] ) ) as $language ) { foreach ( $links->model->get_languages_list( array( 'hide_empty' => $args['hide_if_empty'] ) ) as $language ) {
$id = (int) $language->term_id; $id = (int) $language->term_id;
...@@ -100,7 +100,7 @@ class PLL_Switcher { ...@@ -100,7 +100,7 @@ class PLL_Switcher {
$out[ $slug ] = compact( 'id', 'order', 'slug', 'locale', 'name', 'url', 'flag', 'current_lang', 'no_translation', 'classes' ); $out[ $slug ] = compact( 'id', 'order', 'slug', 'locale', 'name', 'url', 'flag', 'current_lang', 'no_translation', 'classes' );
} }
return empty( $out ) ? array() : $out; return $out;
} }
/** /**
...@@ -187,6 +187,8 @@ class PLL_Switcher { ...@@ -187,6 +187,8 @@ class PLL_Switcher {
// Javascript to switch the language when using a dropdown list // Javascript to switch the language when using a dropdown list
if ( $args['dropdown'] ) { if ( $args['dropdown'] ) {
$urls = array();
foreach ( $links->model->get_languages_list() as $language ) { foreach ( $links->model->get_languages_list() as $language ) {
$url = $links->get_translation_url( $language ); $url = $links->get_translation_url( $language );
$urls[ $language->slug ] = $args['force_home'] || empty( $url ) ? $links->get_home_url( $language ) : $url; $urls[ $language->slug ] = $args['force_home'] || empty( $url ) ? $links->get_home_url( $language ) : $url;
......
...@@ -50,6 +50,7 @@ abstract class PLL_Translated_Object { ...@@ -50,6 +50,7 @@ abstract class PLL_Translated_Object {
$taxonomies = array( $this->tax_language, $this->tax_translations ); $taxonomies = array( $this->tax_language, $this->tax_translations );
// query terms // query terms
$terms = array();
foreach ( wp_get_object_terms( $object_id, $taxonomies, array( 'update_term_meta_cache' => false ) ) as $t ) { foreach ( wp_get_object_terms( $object_id, $taxonomies, array( 'update_term_meta_cache' => false ) ) as $t ) {
$terms[ $t->taxonomy ] = $t; $terms[ $t->taxonomy ] = $t;
if ( $t->taxonomy == $taxonomy ) { if ( $t->taxonomy == $taxonomy ) {
...@@ -239,7 +240,6 @@ abstract class PLL_Translated_Object { ...@@ -239,7 +240,6 @@ abstract class PLL_Translated_Object {
* @return string where clause * @return string where clause
*/ */
public function where_clause( $lang ) { public function where_clause( $lang ) {
global $wpdb;
$tt_id = $this->tax_tt; $tt_id = $this->tax_tt;
// $lang is an object // $lang is an object
...@@ -250,7 +250,8 @@ abstract class PLL_Translated_Object { ...@@ -250,7 +250,8 @@ abstract class PLL_Translated_Object {
// $lang is a comma separated list of slugs ( or an array of slugs ) // $lang is a comma separated list of slugs ( or an array of slugs )
// generally the case is the query is coming from outside with 'lang' parameter // generally the case is the query is coming from outside with 'lang' parameter
$slugs = is_array( $lang ) ? $lang : explode( ',', $lang ); $slugs = is_array( $lang ) ? $lang : explode( ',', $lang );
$languages = array();
foreach ( $slugs as $slug ) { foreach ( $slugs as $slug ) {
$languages[] = absint( $this->model->get_language( $slug )->$tt_id ); $languages[] = absint( $this->model->get_language( $slug )->$tt_id );
} }
......
...@@ -85,7 +85,7 @@ class PLL_Translated_Term extends PLL_Translated_Object { ...@@ -85,7 +85,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
// get_term_by still not cached in WP 3.5.1 but internally, the function is always called by term_id // get_term_by still not cached in WP 3.5.1 but internally, the function is always called by term_id
elseif ( is_string( $value ) && $taxonomy ) { elseif ( is_string( $value ) && $taxonomy ) {
$term_id = wpcom_vip_get_term_by( 'slug', $value, $taxonomy )->term_id; $term_id = get_term_by( 'slug', $value, $taxonomy )->term_id;
} }
// Get the language and make sure it is a PLL_Language object // Get the language and make sure it is a PLL_Language object
...@@ -128,7 +128,7 @@ class PLL_Translated_Term extends PLL_Translated_Object { ...@@ -128,7 +128,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
if ( ! doing_action( 'pre_delete_term' ) && $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $wpdb->terms WHERE term_id = %d;", $id ) ) ) { if ( ! doing_action( 'pre_delete_term' ) && $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $wpdb->terms WHERE term_id = %d;", $id ) ) ) {
// Always keep a group for terms to allow relationships remap when importing from a WXR file // Always keep a group for terms to allow relationships remap when importing from a WXR file
$translations[ $slug ] = $id; $translations = array( $slug => $id );
wp_insert_term( $group = uniqid( 'pll_' ), 'term_translations', array( 'description' => maybe_serialize( $translations ) ) ); wp_insert_term( $group = uniqid( 'pll_' ), 'term_translations', array( 'description' => maybe_serialize( $translations ) ) );
wp_set_object_terms( $id, $group, 'term_translations' ); wp_set_object_terms( $id, $group, 'term_translations' );
} }
...@@ -158,6 +158,8 @@ class PLL_Translated_Term extends PLL_Translated_Object { ...@@ -158,6 +158,8 @@ class PLL_Translated_Term extends PLL_Translated_Object {
* @return array unmodified $terms * @return array unmodified $terms
*/ */
public function _prime_terms_cache( $terms, $taxonomies ) { public function _prime_terms_cache( $terms, $taxonomies ) {
$term_ids = array();
if ( is_array( $terms ) && $this->model->is_translated_taxonomy( $taxonomies ) ) { if ( is_array( $terms ) && $this->model->is_translated_taxonomy( $taxonomies ) ) {
foreach ( $terms as $term ) { foreach ( $terms as $term ) {
$term_ids[] = is_object( $term ) ? $term->term_id : (int) $term; $term_ids[] = is_object( $term ) ? $term->term_id : (int) $term;
......
...@@ -101,8 +101,8 @@ class PLL_Walker_Dropdown extends Walker { ...@@ -101,8 +101,8 @@ class PLL_Walker_Dropdown extends Walker {
$output .= sprintf( $output .= sprintf(
'<select name="%1$s"%2$s%3$s%4$s>' . "\n" . '%5$s' . "\n" . '</select>' . "\n", '<select name="%1$s"%2$s%3$s%4$s>' . "\n" . '%5$s' . "\n" . '</select>' . "\n",
$name = esc_attr( $args['name'] ), esc_attr( $args['name'] ),
isset( $args['id'] ) && ! $args['id'] ? '' : ' id="' . ( empty( $args['id'] ) ? $name : esc_attr( $args['id'] ) ) . '"', isset( $args['id'] ) && ! $args['id'] ? '' : ' id="' . ( empty( $args['id'] ) ? esc_attr( $args['name'] ) : esc_attr( $args['id'] ) ) . '"',
empty( $args['class'] ) ? '' : ' class="' . esc_attr( $args['class'] ) . '"', empty( $args['class'] ) ? '' : ' class="' . esc_attr( $args['class'] ) . '"',
disabled( empty( $args['disabled'] ), false, false ), disabled( empty( $args['disabled'] ), false, false ),
parent::walk( $elements, $max_depth, $args ) parent::walk( $elements, $max_depth, $args )
......
...@@ -64,7 +64,7 @@ class PLL_Widget_Languages extends WP_Widget { ...@@ -64,7 +64,7 @@ class PLL_Widget_Languages extends WP_Widget {
* @return array Settings to save or bool false to cancel saving * @return array Settings to save or bool false to cancel saving
*/ */
public function update( $new_instance, $old_instance ) { public function update( $new_instance, $old_instance ) {
$instance['title'] = sanitize_text_field( $new_instance['title'] ); $instance = array( 'title' => sanitize_text_field( $new_instance['title'] ) );
foreach ( array_keys( PLL_Switcher::get_switcher_options( 'widget' ) ) as $key ) { foreach ( array_keys( PLL_Switcher::get_switcher_options( 'widget' ) ) as $key ) {
$instance[ $key ] = ! empty( $new_instance[ $key ] ) ? 1 : 0; $instance[ $key ] = ! empty( $new_instance[ $key ] ) ? 1 : 0;
} }
......
...@@ -40,7 +40,7 @@ class PLL_Install extends PLL_Install_Base { ...@@ -40,7 +40,7 @@ class PLL_Install extends PLL_Install_Base {
'<div class="error"><p>%s</p></div>', '<div class="error"><p>%s</p></div>',
sprintf( sprintf(
/* translators: 1: Plugin name 2: Current PHP version 3: Required PHP version */ /* translators: 1: Plugin name 2: Current PHP version 3: Required PHP version */
esc_html__( '%1$s has deactivated itself because you are using an old PHP version. You are using using PHP %2$s. %1$s requires PHP %3$s.', 'polylang' ), esc_html__( '%1$s has deactivated itself because you are using an old version of PHP. You are using using PHP %2$s. %1$s requires PHP %3$s.', 'polylang' ),
esc_html( POLYLANG ), esc_html( POLYLANG ),
PHP_VERSION, PHP_VERSION,
esc_html( PLL_MIN_PHP_VERSION ) esc_html( PLL_MIN_PHP_VERSION )
...@@ -62,7 +62,7 @@ class PLL_Install extends PLL_Install_Base { ...@@ -62,7 +62,7 @@ class PLL_Install extends PLL_Install_Base {
'<div class="error"><p>%s</p></div>', '<div class="error"><p>%s</p></div>',
sprintf( sprintf(
/* translators: 1: Plugin name 2: Current WordPress version 3: Required WordPress version */ /* translators: 1: Plugin name 2: Current WordPress version 3: Required WordPress version */
esc_html__( '%1$s has deactivated itself because you are using an old WordPress version. You are using using WordPress %2$s. %1$s requires at least WordPress %3$s.', 'polylang' ), esc_html__( '%1$s has deactivated itself because you are using an old version of WordPress. You are using using WordPress %2$s. %1$s requires at least WordPress %3$s.', 'polylang' ),
esc_html( POLYLANG ), esc_html( POLYLANG ),
esc_html( $wp_version ), esc_html( $wp_version ),
esc_html( PLL_MIN_WP_VERSION ) esc_html( PLL_MIN_WP_VERSION )
......
...@@ -89,7 +89,7 @@ class PLL_Upgrade { ...@@ -89,7 +89,7 @@ class PLL_Upgrade {
* @since 1.2 * @since 1.2
*/ */
public function _upgrade() { public function _upgrade() {
foreach ( array( '0.9', '1.0', '1.1', '1.2', '1.2.1', '1.2.3', '1.3', '1.4', '1.4.1', '1.4.4', '1.5', '1.6', '1.7.4', '1.8', '2.0.8', '2.1', '2.3' ) as $version ) { foreach ( array( '0.9', '1.0', '1.1', '1.2', '1.2.1', '1.2.3', '1.3', '1.4', '1.4.1', '1.4.4', '1.5', '1.6', '1.7.4', '1.8', '2.0.8', '2.1', '2.3', '2.7' ) as $version ) {
if ( version_compare( $this->options['version'], $version, '<' ) ) { if ( version_compare( $this->options['version'], $version, '<' ) ) {
call_user_func( array( $this, 'upgrade_' . str_replace( '.', '_', $version ) ) ); call_user_func( array( $this, 'upgrade_' . str_replace( '.', '_', $version ) ) );
} }
...@@ -143,7 +143,7 @@ class PLL_Upgrade { ...@@ -143,7 +143,7 @@ class PLL_Upgrade {
// Update strings register with icl_register_string // Update strings register with icl_register_string
$strings = get_option( 'polylang_wpml_strings' ); $strings = get_option( 'polylang_wpml_strings' );
if ( $strings ) { if ( $strings ) {
foreach ( $strings as $key => $string ) { foreach ( array_keys( $strings ) as $key ) {
$strings[ $key ]['icl'] = 1; $strings[ $key ]['icl'] = 1;
} }
update_option( 'polylang_wpml_strings', $strings ); update_option( 'polylang_wpml_strings', $strings );
...@@ -179,7 +179,8 @@ class PLL_Upgrade { ...@@ -179,7 +179,8 @@ class PLL_Upgrade {
// Upgrade old model based on metas to new model based on taxonomies // Upgrade old model based on metas to new model based on taxonomies
global $wpdb; global $wpdb;
$wpdb->termmeta = $wpdb->prefix . 'termmeta'; // Registers the termmeta table in wpdb $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // Registers the termmeta table in wpdb
$languages = get_terms( 'language', array( 'hide_empty' => 0 ) ); // Don't use get_languages_list which can't work with the old model $languages = get_terms( 'language', array( 'hide_empty' => 0 ) ); // Don't use get_languages_list which can't work with the old model
$lang_tt_ids = array();
foreach ( $languages as $lang ) { foreach ( $languages as $lang ) {
// First update language with new storage for locale and text direction // First update language with new storage for locale and text direction
...@@ -208,8 +209,12 @@ class PLL_Upgrade { ...@@ -208,8 +209,12 @@ class PLL_Upgrade {
// Translations // Translations
foreach ( array( 'post', 'term' ) as $type ) { foreach ( array( 'post', 'term' ) as $type ) {
$table = $type . 'meta'; $table = $type . 'meta';
$terms = $slugs = $tts = $trs = array(); $terms = array();
$slugs = array();
$tts = array();
$trs = array();
$description = array();
// Get all translated objects // Get all translated objects
// PHPCS:ignore WordPress.DB.PreparedSQL // PHPCS:ignore WordPress.DB.PreparedSQL
...@@ -307,6 +312,8 @@ class PLL_Upgrade { ...@@ -307,6 +312,8 @@ class PLL_Upgrade {
// Multilingal locations and switcher item were stored in a dedicated option // Multilingal locations and switcher item were stored in a dedicated option
if ( version_compare( $this->options['version'], '1.1', '<' ) ) { if ( version_compare( $this->options['version'], '1.1', '<' ) ) {
if ( $menu_lang = get_option( 'polylang_nav_menus' ) ) { if ( $menu_lang = get_option( 'polylang_nav_menus' ) ) {
$locations = array();
foreach ( $menu_lang as $location => $arr ) { foreach ( $menu_lang as $location => $arr ) {
if ( ! in_array( $location, array_keys( get_registered_nav_menus() ) ) ) { if ( ! in_array( $location, array_keys( get_registered_nav_menus() ) ) ) {
continue; continue;
...@@ -355,7 +362,7 @@ class PLL_Upgrade { ...@@ -355,7 +362,7 @@ class PLL_Upgrade {
// Clean the WP option as it was a bad idea to pollute it // Clean the WP option as it was a bad idea to pollute it
if ( version_compare( $this->options['version'], '1.2', '<' ) ) { if ( version_compare( $this->options['version'], '1.2', '<' ) ) {
foreach ( $menus as $loc => $menu ) { foreach ( $menus as $loc => $menu ) {
if ( $pos = strpos( $loc, '#' ) ) { if ( strpos( $loc, '#' ) ) {
unset( $menus[ $loc ] ); unset( $menus[ $loc ] );
} }
} }
...@@ -518,6 +525,8 @@ class PLL_Upgrade { ...@@ -518,6 +525,8 @@ class PLL_Upgrade {
return; return;
} }
$translations_to_load = array();
foreach ( $translations as $translation ) { foreach ( $translations as $translation ) {
if ( in_array( $translation['language'], $languages ) ) { if ( in_array( $translation['language'], $languages ) ) {
$translation['type'] = 'core'; $translation['type'] = 'core';
...@@ -608,4 +617,29 @@ class PLL_Upgrade { ...@@ -608,4 +617,29 @@ class PLL_Upgrade {
protected function upgrade_2_3() { protected function upgrade_2_3() {
delete_transient( 'pll_languages_list' ); delete_transient( 'pll_languages_list' );
} }
/**
* Upgrades if the previous version is < 2.7
* Replace numeric keys by hashes in WPML registered strings
* Dismiss the wizard notice for existing sites
*
* @since 2.7
*/
protected function upgrade_2_7() {
$strings = get_option( 'polylang_wpml_strings' );
if ( is_array( $strings ) ) {
$new_strings = array();
foreach ( $strings as $string ) {
$context = $string['context'];
$name = $string['name'];
$key = md5( "$context | $name" );
$new_strings[ $key ] = $string;
}
update_option( 'polylang_wpml_strings', $new_strings );
}
PLL_Admin_Notices::dismiss( 'wizard' );
}
} }
This diff is collapsed.
jQuery(document).ready(function(e){function t(){var t=e(this).find(":selected"),i=t.data("url");if(i){var n=e(this).iconselectmenu("widget").children(":last"),s=t.data("width"),l=t.data("height");e("<img class='ui-icon' />").prop("src",i).prop("width",s).prop("height",l).appendTo(n)}}var i;e("table.languages").on({focusin:function(){clearTimeout(i),focusedRowActions=e(this).find(".row-actions"),e(".row-actions").not(this).removeClass("visible"),focusedRowActions.addClass("visible")},focusout:function(){i=setTimeout(function(){focusedRowActions.removeClass("visible")},30)}},"tr"),e.widget("custom.iconselectmenu",e.ui.selectmenu,{_renderItem:function(t,i){var n=e("<li>",{text:i.label}),s=e(i.element),l=s.data("url");if(l){var a=s.data("width"),c=s.data("height");e("<img class='ui-icon' />").prop("src",l).prop("width",a).prop("height",c).appendTo(n)}return n.appendTo(t)}}),e("#flag_list").iconselectmenu({create:t,select:t}),e("#lang_list").change(function(){var i=e(this).val().split(":"),n=e("option:selected",this).text().split(" - ");e("#lang_slug").val(i[0]),e("#lang_locale").val(i[1]),e('input[name="rtl"]').val([i[2]]),e("#lang_name").val(n[0]),e('#flag_list option[value="'+i[3]+'"]').attr("selected","selected"),e("#flag_list").iconselectmenu("destroy").iconselectmenu({create:t,select:t})}),e(".translation input").keypress(function(t){13===t.keyCode&&(t.preventDefault(),e("#submit").click())}),e("#the-list").on("click",".configure>a",function(){return e(".pll-configure").hide().prev().show(),e(this).closest("tr").hide().next().show(),!1}),e("#the-list").on("click",".cancel",function(){e(this).closest("tr").hide().prev().show()}),e("#the-list").on("click",".save",function(){var t=e(this).closest("tr"),i=t.attr("id").split("-"),n={action:"pll_save_options",pll_ajax_settings:!0,module:i[i.length-1],_pll_nonce:e("#_pll_nonce").val()};n=t.find(":input").serialize()+"&"+e.param(n),e.post(ajaxurl,n,function(i){var n=wpAjax.parseAjaxResponse(i,"ajax-response");e.each(n.responses,function(){switch(this.what){case"license-update":e("#pll-license-"+this.data).replaceWith(this.supplemental.html);break;case"success":t.hide().prev().show();case"error":e(".settings-error").remove(),e("h1").after(this.data),e(".notice.is-dismissible").each(function(){var t=e(this),i=e('<button type="button" class="notice-dismiss"><span class="screen-reader-text"></span></button>'),n=commonL10n.dismiss||"";i.find(".screen-reader-text").text(n),t.append(i),i.on("click.wp-dismiss-notice",function(i){i.preventDefault(),t.fadeTo(100,0,function(){e(this).slideUp(100,function(){e(this).remove()})})})})}})})}),e(".pll-configure").keypress(function(t){13===t.keyCode&&(t.preventDefault(),e(this).find(".save").click()),27===t.keyCode&&(t.preventDefault(),e(this).find(".cancel").click())}),e("input[name='force_lang']").change(function(){function t(e,t){t?e.show():e.hide()}var i=e(this).val();t(e("#pll-domains-table"),3==i),t(e("#pll-hide-default"),3>i),t(e("#pll-rewrite"),2>i),t(e("#pll-redirect-lang"),2>i)}),e(".pll-deactivate-license").on("click",function(){var t={action:"pll_deactivate_license",pll_ajax_settings:!0,id:e(this).attr("id"),_pll_nonce:e("#_pll_nonce").val()};e.post(ajaxurl,t,function(t){e("#pll-license-"+t.id).replaceWith(t.html)})})}); jQuery(document).ready(function(e){var t;e("table.languages").on({focusin:function(){clearTimeout(t),focusedRowActions=e(this).find(".row-actions"),e(".row-actions").not(this).removeClass("visible"),focusedRowActions.addClass("visible")},focusout:function(){t=setTimeout(function(){focusedRowActions.removeClass("visible")},30)}},"tr");var n=function(t,n){var s=e("<li>").text(n.label).prepend(e(n.element).data("flag-html"));return s.children("img").addClass("ui-icon"),s.appendTo(t)},s=function(t){var n=e(t).selectmenu("instance").buttonText;n.prepend(e(t).children(":selected").data("flag-html")),n.children("img").addClass("ui-icon")};e("#flag_list").on("selectmenucreate selectmenuselect",function(){s(this)}),e("#flag_list").on("selectmenuopen",function(){e(this).selectmenu("refresh").trigger("selectmenuselect")}),e("#flag_list").selectmenu({width:"100%"}),e("#flag_list").selectmenu("instance")._renderItem=n,e("#lang_list").on("selectmenucreate selectmenuselect",function(){s(this)}),e("#lang_list").selectmenu({width:"100%"}),e("#lang_list").selectmenu("instance")._renderItem=n,e("#add-lang #lang_list").on("selectmenuchange",function(){var t=e(this).val().split(":"),n=e("option:selected",this).text().split(" - ");e("#lang_slug").val(t[0]),e("#lang_locale").val(t[1]),e('input[name="rtl"]').val([t[2]]),e("#lang_name").val(n[0]),e("#flag_list").val(t[3]),e("#flag_list").selectmenu("refresh").trigger("selectmenuselect")}),e(".translation input").keypress(function(t){13===t.keyCode&&(t.preventDefault(),e("#submit").click())}),e("#the-list").on("click",".configure>a",function(){return e(".pll-configure").hide().prev().show(),e(this).closest("tr").hide().next().show(),!1}),e("#the-list").on("click",".cancel",function(){e(this).closest("tr").hide().prev().show()}),e("#the-list").on("click",".save",function(){var t=e(this).closest("tr"),n=t.attr("id").split("-"),s={action:"pll_save_options",pll_ajax_settings:!0,module:n[n.length-1],_pll_nonce:e("#_pll_nonce").val()};s=t.find(":input").serialize()+"&"+e.param(s),e.post(ajaxurl,s,function(n){var s=wpAjax.parseAjaxResponse(n,"ajax-response");e.each(s.responses,function(){switch(this.what){case"license-update":e("#pll-license-"+this.data).replaceWith(this.supplemental.html);break;case"success":t.hide().prev().show();case"error":e(".settings-error").remove(),e("h1").after(this.data),e(".notice.is-dismissible").each(function(){var t=e(this),n=e('<button type="button" class="notice-dismiss"><span class="screen-reader-text"></span></button>'),s=commonL10n.dismiss||"";n.find(".screen-reader-text").text(s),t.append(n),n.on("click.wp-dismiss-notice",function(n){n.preventDefault(),t.fadeTo(100,0,function(){e(this).slideUp(100,function(){e(this).remove()})})})})}})})}),e(".pll-configure").keypress(function(t){13===t.keyCode&&(t.preventDefault(),e(this).find(".save").click()),27===t.keyCode&&(t.preventDefault(),e(this).find(".cancel").click())}),e("input[name='force_lang']").change(function(){function t(e,t){t?e.show():e.hide()}var n=e(this).val();t(e("#pll-domains-table"),3==n),t(e("#pll-hide-default"),3>n),t(e("#pll-rewrite"),2>n),t(e("#pll-redirect-lang"),2>n)}),e(".pll-deactivate-license").on("click",function(){var t={action:"pll_deactivate_license",pll_ajax_settings:!0,id:e(this).attr("id"),_pll_nonce:e("#_pll_nonce").val()};e.post(ajaxurl,t,function(t){e("#pll-license-"+t.id).replaceWith(t.html)})}),e(".if-js-closed").removeClass("if-js-closed").addClass("closed"),"undefined"!=typeof postboxes&&postboxes.add_postbox_toggles(pagenow)});
wp.apiFetch.use(function(options,next){if('undefined'===typeof options.url){if('undefined'===typeof options.data){options.path+=((options.path.indexOf('?')>=0)?'&lang=':'?lang=')+getCurrentLanguage()}else{options.data.lang=getCurrentLanguage()}}return next(options)});function getCurrentLanguage(){return document.querySelector('[name=post_lang_choice]').value}jQuery(document).ready(function($){$('.post_lang_choice').change(function(){const select=wp.data.select;const dispatch=wp.data.dispatch;const subscribe=wp.data.subscribe;let unsubscribe=null;const savePostIsDone=new Promise(function(resolve,reject){unsubscribe=subscribe(function(){const isSavePostSucceeded=select('core/editor').didPostSaveRequestSucceed();const isSavePostFailed=select('core/editor').didPostSaveRequestFail();if(isSavePostSucceeded||isSavePostFailed){if(isSavePostFailed){reject()}else{resolve()}}})});if(location.pathname.match(/post-new.php/gi)){const title=select('core/editor').getEditedPostAttribute('title');const content=select('core/editor').getEditedPostAttribute('content');const excerpt=select('core/editor').getEditedPostAttribute('excerpt');if(''===title&&''===content&&''===excerpt){if(-1!=location.search.indexOf('new_lang')){window.location.search=window.location.search.replace(/(?:new_lang=[^&]*)(&)?(.*)/,'new_lang='+this.value+'$1$2');}else{window.location.search=window.location.search+((-1!=window.location.search.indexOf('?'))?'&':'?')+'new_lang='+this.value}}}dispatch('core/editor').savePost();savePostIsDone.then(function(){unsubscribe();window.location.reload()},function(){unsubscribe()}).catch(function(){unsubscribe()})})});jQuery(document).ready(function($){$('.post_lang_choice').change(function(){var data={action:'post_lang_choice',lang:$(this).val(),post_type:$('#post_type').val(),post_id:$('#post_ID').val(),_pll_nonce:$('#_pll_nonce').val()};$.post(ajaxurl,data,function(response){var res=wpAjax.parseAjaxResponse(response,'ajax-response');$.each(res.responses,function(){switch(this.what){case 'translations':$('.translations').html(this.data);init_translations();break;case 'flag':$('.pll-select-flag').html(this.data);break}})})});function init_translations(){$('.tr_lang').each(function(){var tr_lang=$(this).attr('id').substring(8);var td=$(this).parent().parent().siblings('.pll-edit-column');$(this).autocomplete({minLength:0,source:ajaxurl+'?action=pll_posts_not_translated&post_language='+$('.post_lang_choice').val()+'&translation_language='+tr_lang+'&post_type='+$('#post_type').val()+'&_pll_nonce='+$('#_pll_nonce').val(),select:function(event,ui){$('#htr_lang_'+tr_lang).val(ui.item.id);td.html(ui.item.link)}});$(this).blur(function(){if(!$(this).val()){$('#htr_lang_'+tr_lang).val(0);td.html(td.siblings('.hidden').children().clone())}})})}init_translations();$('#ml_box').on('click','.pll-button',function(){var value=$(this).hasClass('wp-ui-text-highlight');var id=$(this).attr('id');var post_id=$('#htr_lang_'+id.replace('pll_sync_post[','').replace(']','')).val();if('undefined'==typeof(post_id)||0==post_id||value||confirm(confirm_text)){var data={action:'toggle_'+id,value:value,post_type:$('#post_type').val(),_pll_nonce:$('#_pll_nonce').val()};$.post(ajaxurl,data,function(response){var res=wpAjax.parseAjaxResponse(response,'ajax-response');$.each(res.responses,function(){id=id.replace('[','\\[').replace(']','\\]');$('#'+id).toggleClass('wp-ui-text-highlight').attr('title',this.data).children('span').html(this.data);$('input[name="'+id+'"]').val(!data['value'])})})}})}); function getCurrentLanguage(){return document.querySelector("[name=post_lang_choice]").value}wp.apiFetch.use(function(t,e){return void 0===t.url&&(void 0===t.data?t.path+=(t.path.indexOf("?")>=0?"&lang=":"?lang=")+getCurrentLanguage():t.data.lang=getCurrentLanguage()),e(t)}),jQuery(document).ready(function(t){t(".post_lang_choice").change(function(){const t=wp.data.select,e=wp.data.dispatch,n=wp.data.subscribe;let a=null;const o=new Promise(function(e,o){a=n(function(){const n=t("core/editor").didPostSaveRequestSucceed(),a=t("core/editor").didPostSaveRequestFail();(n||a)&&(a?o():e())})});if(location.pathname.match(/post-new.php/gi)){const e=t("core/editor").getEditedPostAttribute("title"),n=t("core/editor").getEditedPostAttribute("content"),a=t("core/editor").getEditedPostAttribute("excerpt");""===e&&""===n&&""===a&&(-1!=location.search.indexOf("new_lang")?window.location.search=window.location.search.replace(/(?:new_lang=[^&]*)(&)?(.*)/,"new_lang="+this.value+"$1$2"):window.location.search=window.location.search+(-1!=window.location.search.indexOf("?")?"&":"?")+"new_lang="+this.value)}e("core/editor").savePost(),o.then(function(){a(),window.location.reload()},function(){a()}).catch(function(){a()})})}),jQuery(document).ready(function(t){function e(){t(".tr_lang").each(function(){var e=t(this).attr("id").substring(8),n=t(this).parent().parent().siblings(".pll-edit-column");t(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+t(".post_lang_choice").val()+"&translation_language="+e+"&post_type="+t("#post_type").val()+"&_pll_nonce="+t("#_pll_nonce").val(),select:function(a,o){t("#htr_lang_"+e).val(o.item.id),n.html(o.item.link)}}),t(this).blur(function(){t(this).val()||(t("#htr_lang_"+e).val(0),n.html(n.siblings(".hidden").children().clone()))})})}t(".post_lang_choice").change(function(){var n={action:"post_lang_choice",lang:t(this).val(),post_type:t("#post_type").val(),post_id:t("#post_ID").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,n,function(n){var a=wpAjax.parseAjaxResponse(n,"ajax-response");t.each(a.responses,function(){switch(this.what){case"translations":t(".translations").html(this.data),e();break;case"flag":t(".pll-select-flag").html(this.data)}})})}),e(),t("#ml_box").on("click",".pll-button",function(){var e=t(this).hasClass("wp-ui-text-highlight"),n=t(this).attr("id"),a=t("#htr_lang_"+n.replace("pll_sync_post[","").replace("]","")).val();if(void 0===a||0==a||e||confirm(confirm_text)){var o={action:"toggle_"+n,value:e,post_type:t("#post_type").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,o,function(e){var a=wpAjax.parseAjaxResponse(e,"ajax-response");t.each(a.responses,function(){n=n.replace("[","\\[").replace("]","\\]"),t("#"+n).toggleClass("wp-ui-text-highlight").attr("title",this.data).children("span").text(this.data),t('input[name="'+n+'"]').val(!o.value)})})}})});
\ No newline at end of file
!function(t){t.ajaxPrefilter(function(a){"string"==typeof a.data&&-1!==a.url.indexOf("action=ajax-tag-search")&&(lang=t(".post_lang_choice").val())&&(a.data="lang="+lang+"&"+a.data)})}(jQuery),function(t){tagBox.get=function(a){var l=a.substr(a.indexOf("-")+1),n={action:"get-tagcloud",lang:t(".post_lang_choice").val(),tax:l};t.post(ajaxurl,n,function(n,e){0!=n&&"success"==e||(n=wpAjax.broken),n=t('<div id="tagcloud-'+l+'" class="the-tagcloud">'+n+"</div>"),t("a",n).click(function(){return tagBox.flushTags(t(this).closest(".inside").children(".tagsdiv"),this),!1}),(v=t(".the-tagcloud").css("display"))?(t(".the-tagcloud").replaceWith(n),t(".the-tagcloud").css("display",v)):t("#"+a).after(n)})}}(jQuery),jQuery(document).ready(function(t){function a(){t(".tr_lang").each(function(){var a=t(this).attr("id").substring(8),l=t(this).parent().parent().siblings(".pll-edit-column");t(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+t(".post_lang_choice").val()+"&translation_language="+a+"&post_type="+t("#post_type").val()+"&_pll_nonce="+t("#_pll_nonce").val(),select:function(n,e){t("#htr_lang_"+a).val(e.item.id),l.html(e.item.link)}}),t(this).blur(function(){t(this).val()||(t("#htr_lang_"+a).val(0),l.html(l.siblings(".hidden").children().clone()))})})}var l=new Array;t(".categorydiv").each(function(){var a,n,e=t(this).attr("id");a=e.split("-"),a.shift(),n=a.join("-"),l.push(n),t("#"+n+"-add-submit").before(t("<input />").attr("type","hidden").attr("id",n+"-lang").attr("name","term_lang_choice").attr("value",t(".post_lang_choice").val()))}),t(".post_lang_choice").change(function(){var n=t(this).val(),e=t(this).children('option[value="'+n+'"]').attr("lang"),i=t('.pll-translation-column > span[lang="'+e+'"]').attr("dir"),s={action:"post_lang_choice",lang:n,post_type:t("#post_type").val(),taxonomies:l,post_id:t("#post_ID").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,s,function(l){var n=wpAjax.parseAjaxResponse(l,"ajax-response");t.each(n.responses,function(){switch(this.what){case"translations":t(".translations").html(this.data),a();break;case"taxonomy":var l=this.data;t("#"+l+"checklist").html(this.supplemental.all),t("#"+l+"checklist-pop").html(this.supplemental.populars),t("#new"+l+"_parent").replaceWith(this.supplemental.dropdown),t("#"+l+"-lang").val(t(".post_lang_choice").val());break;case"pages":t("#parent_id").html(this.data);break;case"flag":t(".pll-select-flag").html(this.data);break;case"permalink":var n=t("#edit-slug-box");"-1"!=this.data&&n.children().length&&n.html(this.data)}}),t(".tagcloud-link").each(function(){var a=t(this).attr("id");tagBox.get(a)}),t("body").removeClass("pll-dir-rtl").removeClass("pll-dir-ltr").addClass("pll-dir-"+i),t("#content_ifr").contents().find("html").attr("lang",e).attr("dir",i),t("#content_ifr").contents().find("body").attr("dir",i)})}),a(),t("#ml_box").on("click",".pll-button",function(){var a=t(this).hasClass("wp-ui-text-highlight"),l=t(this).attr("id"),n=t("#htr_lang_"+l.replace("pll_sync_post[","").replace("]","")).val();if("undefined"==typeof n||0==n||a||confirm(confirm_text)){var e={action:"toggle_"+l,value:a,post_type:t("#post_type").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,e,function(a){var n=wpAjax.parseAjaxResponse(a,"ajax-response");t.each(n.responses,function(){l=l.replace("[","\\[").replace("]","\\]"),t("#"+l).toggleClass("wp-ui-text-highlight").attr("title",this.data).children("span").html(this.data),t('input[name="'+l+'"]').val(!e.value)})})}})}); !function(t){t.ajaxPrefilter(function(a,l,n){"string"==typeof a.data&&-1!==a.url.indexOf("action=ajax-tag-search")&&(lang=t(".post_lang_choice").val())&&(a.data="lang="+lang+"&"+a.data)})}(jQuery),function(t){tagBox.get=function(a){var l=a.substr(a.indexOf("-")+1),n={action:"get-tagcloud",lang:t(".post_lang_choice").val(),tax:l};t.post(ajaxurl,n,function(n,e){0!=n&&"success"==e||(n=wpAjax.broken),n=t("<div />").addClass("the-tagcloud").attr("id","tagcloud-"+l).html(n),t("a",n).click(function(){return tagBox.flushTags(t(this).closest(".inside").children(".tagsdiv"),this),!1}),(v=t(".the-tagcloud").css("display"))?(t(".the-tagcloud").replaceWith(n),t(".the-tagcloud").css("display",v)):t("#"+a).after(n)})}}(jQuery),jQuery(document).ready(function(t){var a=new Array;function l(){t(".tr_lang").each(function(){var a=t(this).attr("id").substring(8),l=t(this).parent().parent().siblings(".pll-edit-column");t(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+t(".post_lang_choice").val()+"&translation_language="+a+"&post_type="+t("#post_type").val()+"&_pll_nonce="+t("#_pll_nonce").val(),select:function(n,e){t("#htr_lang_"+a).val(e.item.id),l.html(e.item.link)}}),t(this).blur(function(){t(this).val()||(t("#htr_lang_"+a).val(0),l.html(l.siblings(".hidden").children().clone()))})})}t(".categorydiv").each(function(){var l,n;(l=t(this).attr("id").split("-")).shift(),n=l.join("-"),a.push(n),t("#"+n+"-add-submit").before(t("<input />").attr("type","hidden").attr("id",n+"-lang").attr("name","term_lang_choice").attr("value",t(".post_lang_choice").val()))}),t(".post_lang_choice").change(function(){var n=t(this).val(),e=t(this).children('option[value="'+n+'"]').attr("lang"),i=t('.pll-translation-column > span[lang="'+e+'"]').attr("dir"),s={action:"post_lang_choice",lang:n,post_type:t("#post_type").val(),taxonomies:a,post_id:t("#post_ID").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,s,function(a){var n=wpAjax.parseAjaxResponse(a,"ajax-response");t.each(n.responses,function(){switch(this.what){case"translations":t(".translations").html(this.data),l();break;case"taxonomy":var a=this.data;t("#"+a+"checklist").html(this.supplemental.all),t("#"+a+"checklist-pop").html(this.supplemental.populars),t("#new"+a+"_parent").replaceWith(this.supplemental.dropdown),t("#"+a+"-lang").val(t(".post_lang_choice").val());break;case"pages":t("#parent_id").html(this.data);break;case"flag":t(".pll-select-flag").html(this.data);break;case"permalink":var n=t("#edit-slug-box");"-1"!=this.data&&n.children().length&&n.html(this.data)}}),t(".tagcloud-link").each(function(){var a=t(this).attr("id");tagBox.get(a)}),t("body").removeClass("pll-dir-rtl").removeClass("pll-dir-ltr").addClass("pll-dir-"+i),t("#content_ifr").contents().find("html").attr("lang",e).attr("dir",i),t("#content_ifr").contents().find("body").attr("dir",i)})}),l(),t("#ml_box").on("click",".pll-button",function(){var a=t(this).hasClass("wp-ui-text-highlight"),l=t(this).attr("id"),n=t("#htr_lang_"+l.replace("pll_sync_post[","").replace("]","")).val();if(void 0===n||0==n||a||confirm(confirm_text)){var e={action:"toggle_"+l,value:a,post_type:t("#post_type").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,e,function(a){var n=wpAjax.parseAjaxResponse(a,"ajax-response");t.each(n.responses,function(){l=l.replace("[","\\[").replace("]","\\]"),t("#"+l).toggleClass("wp-ui-text-highlight").attr("title",this.data).children("span").text(this.data),t('input[name="'+l+'"]').val(!e.value)})})}})});
\ No newline at end of file
jQuery( document ).ready(function( $ ) { jQuery( document ).ready(
$( '#update-nav-menu' ).bind( 'click', function( e ) { function( $ ) {
if ( e.target && e.target.className && -1 != e.target.className.indexOf( 'item-edit' ) ) { $( '#update-nav-menu' ).bind(
$( "input[value='#pll_switcher'][type=text]" ).parent().parent().parent().each(function(){ 'click',
var item = $( this ).attr( 'id' ).substring( 19 ); function( e ) {
$( this ).children( 'p:not( .field-move )' ).remove(); // remove default fields we don't need if ( e.target && e.target.className && -1 != e.target.className.indexOf( 'item-edit' ) ) {
$( "input[value='#pll_switcher'][type=text]" ).parent().parent().parent().each(
function(){
var item = $( this ).attr( 'id' ).substring( 19 );
$( this ).children( 'p:not( .field-move )' ).remove(); // remove default fields we don't need
h = $( '<input>' ).attr({ // item is a number part of id of parent menu item built by WordPress
type: 'hidden', // pll_data is built server side with i18n strings without HTML and data retrieved from post meta
id: 'edit-menu-item-title-' + item, // the usage of attr method is safe before append call.
name: 'menu-item-title[' + item + ']', h = $( '<input>' ).attr(
value: pll_data.title {
}); type: 'hidden',
$( this ).append( h ); id: 'edit-menu-item-title-' + item,
name: 'menu-item-title[' + item + ']',
value: pll_data.title
}
);
$( this ).append( h ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
h = $( '<input>' ).attr({ h = $( '<input>' ).attr(
type: 'hidden', {
id: 'edit-menu-item-url-' + item, type: 'hidden',
name: 'menu-item-url[' + item + ']', id: 'edit-menu-item-url-' + item,
value: '#pll_switcher' name: 'menu-item-url[' + item + ']',
}); value: '#pll_switcher'
$( this ).append( h ); }
);
$( this ).append( h ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
// a hidden field which exits only if our jQuery code has been executed // a hidden field which exits only if our jQuery code has been executed
h = $( '<input>' ).attr({ h = $( '<input>' ).attr(
type: 'hidden', {
id: 'edit-menu-item-pll-detect-' + item, type: 'hidden',
name: 'menu-item-pll-detect[' + item + ']', id: 'edit-menu-item-pll-detect-' + item,
value: 1 name: 'menu-item-pll-detect[' + item + ']',
}); value: 1
$( this ).append( h ); }
);
$( this ).append( h ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
ids = Array( 'hide_if_no_translation', 'hide_current', 'force_home', 'show_flags', 'show_names', 'dropdown' ); // reverse order ids = Array( 'hide_if_no_translation', 'hide_current', 'force_home', 'show_flags', 'show_names', 'dropdown' ); // reverse order
// add the fields // add the fields
for ( var i = 0; i < ids.length; i++ ) { for ( var i = 0, idsLength = ids.length; i < idsLength; i++ ) {
p = $( '<p>' ).attr( 'class', 'description' ); p = $( '<p>' ).attr( 'class', 'description' );
$( this ).prepend( p ); $( this ).prepend( p );
label = $( '<label>' ).attr( 'for', 'edit-menu-item-' + ids[ i ] + '-' + item ).text( ' ' + pll_data.strings[ ids[ i ] ] ); // item is a number part of id of parent menu item built by WordPress
p.append( label ); // pll_data is built server side with i18n strings without HTML
cb = $( '<input>' ).attr({ label = $( '<label>' ).attr( 'for', 'edit-menu-item-' + ids[ i ] + '-' + item ).text( ' ' + pll_data.strings[ ids[ i ] ] );
type: 'checkbox', p.append( label ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
id: 'edit-menu-item-' + ids[ i ] + '-' + item, cb = $( '<input>' ).attr(
name: 'menu-item-' + ids[ i ] + '[' + item + ']', {
value: 1 type: 'checkbox',
}); id: 'edit-menu-item-' + ids[ i ] + '-' + item,
if ( ( typeof( pll_data.val[ item ] ) != 'undefined' && pll_data.val[ item ][ ids[ i ] ] == 1 ) || ( typeof( pll_data.val[ item ] ) == 'undefined' && ids[ i ] == 'show_names' ) ) { // show_names as default value name: 'menu-item-' + ids[ i ] + '[' + item + ']',
cb.prop( 'checked', true ); value: 1
} }
label.prepend( cb ); );
} if ( ( typeof( pll_data.val[ item ] ) != 'undefined' && pll_data.val[ item ][ ids[ i ] ] == 1 ) || ( typeof( pll_data.val[ item ] ) == 'undefined' && ids[ i ] == 'show_names' ) ) { // show_names as default value
}); cb.prop( 'checked', true );
}
label.prepend( cb );
}
}
);
// disallow unchecking both show names and show flags // disallow unchecking both show names and show flags
$( '.menu-item-data-object-id' ).each(function() { $( '.menu-item-data-object-id' ).each(
var id = $( this ).val(); function() {
var options = ['names-', 'flags-']; var id = $( this ).val();
$.each( options, function( i, v ) { var options = ['names-', 'flags-'];
$( '#edit-menu-item-show_' + v + id ).change(function() { $.each(
if ( 'checked' != $( this ).attr( 'checked' ) ) { options,
$( '#edit-menu-item-show_' + options[ 1 - i ] + id ).prop( 'checked', true ); function( i, v ) {
$( '#edit-menu-item-show_' + v + id ).change(
function() {
if ( 'checked' != $( this ).attr( 'checked' ) ) {
$( '#edit-menu-item-show_' + options[ 1 - i ] + id ).prop( 'checked', true );
}
}
);
}
);
} }
}); );
}); }
}); }
} );
}); }
}); );
jQuery(document).ready(function(a){a("#update-nav-menu").bind("click",function(b){if(b.target&&b.target.className&&-1!=b.target.className.indexOf("item-edit")){a("input[value='#pll_switcher'][type=text]").parent().parent().parent().each(function(){var d=a(this).attr("id").substring(19);a(this).children("p:not( .field-move )").remove();h=a("<input>").attr({type:"hidden",id:"edit-menu-item-title-"+d,name:"menu-item-title["+d+"]",value:pll_data.title});a(this).append(h);h=a("<input>").attr({type:"hidden",id:"edit-menu-item-url-"+d,name:"menu-item-url["+d+"]",value:"#pll_switcher"});a(this).append(h);h=a("<input>").attr({type:"hidden",id:"edit-menu-item-pll-detect-"+d,name:"menu-item-pll-detect["+d+"]",value:1});a(this).append(h);ids=Array("hide_if_no_translation","hide_current","force_home","show_flags","show_names","dropdown");for(var c=0;c<ids.length;c++){p=a("<p>").attr("class","description");a(this).prepend(p);label=a("<label>").attr("for","edit-menu-item-"+ids[c]+"-"+d).text(" "+pll_data.strings[ids[c]]);p.append(label);cb=a("<input>").attr({type:"checkbox",id:"edit-menu-item-"+ids[c]+"-"+d,name:"menu-item-"+ids[c]+"["+d+"]",value:1});if((typeof(pll_data.val[d])!="undefined"&&pll_data.val[d][ids[c]]==1)||(typeof(pll_data.val[d])=="undefined"&&ids[c]=="show_names")){cb.prop("checked",true)}label.prepend(cb)}});a(".menu-item-data-object-id").each(function(){var d=a(this).val();var c=["names-","flags-"];a.each(c,function(f,e){a("#edit-menu-item-show_"+e+d).change(function(){if("checked"!=a(this).attr("checked")){a("#edit-menu-item-show_"+c[1-f]+d).prop("checked",true)}})})})}})}); jQuery(document).ready(function(e){e("#update-nav-menu").bind("click",function(t){t.target&&t.target.className&&-1!=t.target.className.indexOf("item-edit")&&(e("input[value='#pll_switcher'][type=text]").parent().parent().parent().each(function(){var t=e(this).attr("id").substring(19);e(this).children("p:not( .field-move )").remove(),h=e("<input>").attr({type:"hidden",id:"edit-menu-item-title-"+t,name:"menu-item-title["+t+"]",value:pll_data.title}),e(this).append(h),h=e("<input>").attr({type:"hidden",id:"edit-menu-item-url-"+t,name:"menu-item-url["+t+"]",value:"#pll_switcher"}),e(this).append(h),h=e("<input>").attr({type:"hidden",id:"edit-menu-item-pll-detect-"+t,name:"menu-item-pll-detect["+t+"]",value:1}),e(this).append(h),ids=Array("hide_if_no_translation","hide_current","force_home","show_flags","show_names","dropdown");for(var i=0,a=ids.length;i<a;i++)p=e("<p>").attr("class","description"),e(this).prepend(p),label=e("<label>").attr("for","edit-menu-item-"+ids[i]+"-"+t).text(" "+pll_data.strings[ids[i]]),p.append(label),cb=e("<input>").attr({type:"checkbox",id:"edit-menu-item-"+ids[i]+"-"+t,name:"menu-item-"+ids[i]+"["+t+"]",value:1}),(void 0!==pll_data.val[t]&&1==pll_data.val[t][ids[i]]||void 0===pll_data.val[t]&&"show_names"==ids[i])&&cb.prop("checked",!0),label.prepend(cb)}),e(".menu-item-data-object-id").each(function(){var t=e(this).val(),i=["names-","flags-"];e.each(i,function(a,n){e("#edit-menu-item-show_"+n+t).change(function(){"checked"!=e(this).attr("checked")&&e("#edit-menu-item-show_"+i[1-a]+t).prop("checked",!0)})})}))})});
\ No newline at end of file
This diff is collapsed.
!function(t){t.ajaxPrefilter(function(n){"string"==typeof n.data&&-1!==n.data.indexOf("action=ajax-tag-search")&&(lang=t(':input[name="inline_lang_choice"]').val())&&(n.data="lang="+lang+"&"+n.data)})}(jQuery),function(t){t(document).bind("DOMNodeInserted",function(n){function a(n){"undefined"!=typeof pll_term_languages&&t.each(pll_term_languages,function(a,e){t.each(e,function(e,i){t.each(i,function(i){id="#"+e+"-"+pll_term_languages[a][e][i],n==a?t(id).show():t(id).hide()})})})}function e(n){"undefined"!=typeof pll_page_languages&&t.each(pll_page_languages,function(a,e){t.each(e,function(e){v=t('#post_parent option[value="'+pll_page_languages[a][e]+'"]'),n==a?v.show():v.hide()})})}var i=t(n.target);if("inline-edit"==i.attr("id")){var l=i.prev().attr("id").replace("post-","");if(l>0){var c=i.find(':input[name="inline_lang_choice"]'),s=t("#lang_"+l).html();c.val(s),a(s),e(s),c.change(function(){a(t(this).val()),e(t(this).val())})}}})}(jQuery),function(t){t(document).ajaxSuccess(function(n,a,e){function i(n){var a=new Array;t(".translation_"+n).each(function(){a.push(t(this).parent().parent().attr("id").substring(5))});var e={action:"pll_update_post_rows",post_id:n,translations:a.join(","),post_type:t("input[name='post_type']").val(),screen:t("input[name='screen']").val(),_pll_nonce:t("input[name='_inline_edit']").val()};t.post(ajaxurl,e,function(n){if(n){var a=wpAjax.parseAjaxResponse(n,"ajax-response");t.each(a.responses,function(){"row"==this.what&&t("#post-"+this.supplemental.post_id).replaceWith(this.data)})}})}if("string"==typeof e.data){var l=wpAjax.unserialize(e.data);"undefined"!=typeof l.action&&"inline-save"==l.action&&i(l.post_ID)}})}(jQuery),function(t){t.ajaxPrefilter(function(n){"string"==typeof n.data&&-1!==n.data.indexOf("action=find_posts")&&(n.data="pll_post_id="+t("#affected").val()+"&"+n.data)})}(jQuery),jQuery(document).ready(function(t){var n=this;t(".editinline").click(function(){t("#pll-translate").find(".cancel").click()}),t("#doaction, #doaction2").click(function(a){n.whichBulkButtonId=t(this).attr("id");var e=n.whichBulkButtonId.substr(2);"pll_translate"===t('select[name="'+e+'"]').val()?(a.preventDefault(),"undefined"!=typeof inlineEditPost&&inlineEditPost.revert(),t("#pll-translate td").attr("colspan",t("th:visible, td:visible",".widefat:first thead").length),t("table.widefat tbody").prepend(t("#pll-translate")).prepend('<tr class="hidden"></tr>')):t("#pll-translate").find(".cancel").click()}),t("#pll-translate").on("click",".cancel",function(){t("#pll-translate").siblings(".hidden").remove(),t("#pll-bulk-translate").append(t("#pll-translate")),t("#"+n.whichBulkButtonId).focus()}),t("#pll-translate").keydown(function(n){13!==n.keyCode||t(n.target).hasClass("cancel")||(n.preventDefault(),t(this).find("input[type=submit]").click()),27===n.keyCode&&(n.preventDefault(),t(this).find(".cancel").click())})}); !function(t){t.ajaxPrefilter(function(n){"string"==typeof n.data&&-1!==n.data.indexOf("action=ajax-tag-search")&&(lang=t(':input[name="inline_lang_choice"]').val())&&(n.data="lang="+lang+"&"+n.data)})}(jQuery),function(t){t(document).bind("DOMNodeInserted",function(n){function e(n){"undefined"!=typeof pll_term_languages&&t.each(pll_term_languages,function(e,a){t.each(a,function(a,i){t.each(i,function(i){id="#"+a+"-"+pll_term_languages[e][a][i],n==e?t(id).show():t(id).hide()})})})}function a(n){"undefined"!=typeof pll_page_languages&&t.each(pll_page_languages,function(e,a){t.each(a,function(a){v=t('#post_parent option[value="'+pll_page_languages[e][a]+'"]'),n==e?v.show():v.hide()})})}var i=t(n.target);if("inline-edit"==i.attr("id")){var l=i.prev().attr("id").replace("post-","");if(l>0){var c=i.find(':input[name="inline_lang_choice"]'),o=t("#lang_"+l).html();c.val(o),e(o),a(o),c.change(function(){e(t(this).val()),a(t(this).val())})}}})}(jQuery),function(t){t(document).ajaxSuccess(function(n,e,a){function i(n){var e=new Array;t(".translation_"+n).each(function(){e.push(t(this).parent().parent().attr("id").substring(5))});var a={action:"pll_update_post_rows",post_id:n,translations:e.join(","),post_type:t("input[name='post_type']").val(),screen:t("input[name='screen']").val(),_pll_nonce:t("input[name='_inline_edit']").val()};t.post(ajaxurl,a,function(n){if(n){var e=wpAjax.parseAjaxResponse(n,"ajax-response");t.each(e.responses,function(){"row"==this.what&&t("#post-"+this.supplemental.post_id).replaceWith(this.data)})}})}if("string"==typeof a.data){var l=wpAjax.unserialize(a.data);"undefined"!=typeof l.action&&"inline-save"==l.action&&i(l.post_ID)}})}(jQuery),function(t){t.ajaxPrefilter(function(n){"string"==typeof n.data&&-1!==n.data.indexOf("action=find_posts")&&(n.data="pll_post_id="+t("#affected").val()+"&"+n.data)})}(jQuery),jQuery(document).ready(function(t){var n=this;t(".editinline").click(function(){t("#pll-translate").find(".cancel").click()}),t("#doaction, #doaction2").click(function(e){n.whichBulkButtonId=t(this).attr("id");var a=n.whichBulkButtonId.substr(2);"pll_translate"===t('select[name="'+a+'"]').val()?(e.preventDefault(),"undefined"!=typeof inlineEditPost&&inlineEditPost.revert(),t("#pll-translate td").attr("colspan",t("th:visible, td:visible",".widefat:first thead").length),t("table.widefat tbody").prepend(t("#pll-translate")).prepend('<tr class="hidden"></tr>')):t("#pll-translate").find(".cancel").click()}),t("#pll-translate").on("click",".cancel",function(){t("#pll-translate").siblings(".hidden").remove(),t("#pll-bulk-translate").append(t("#pll-translate")),t("#"+n.whichBulkButtonId).focus()}),t("#pll-translate").keydown(function(n){13!==n.keyCode||t(n.target).hasClass("cancel")||(n.preventDefault(),t(this).find("input[type=submit]").click()),27===n.keyCode&&(n.preventDefault(),t(this).find(".cancel").click())}),t("#posts-filter").on("submit",function(){t(".settings-error").remove(),setTimeout(function(){t("input[type=checkbox]:checked").attr("checked",!1),t("#pll-translate").find(".cancel").trigger("click")},500)})});
This diff is collapsed.
!function(a){a(document).bind("DOMNodeInserted",function(t){var n=a(t.target);if("inline-edit"==n.attr("id")){var e=n.prev().attr("id").replace("tag-","");if(e>0){var l=n.find(':input[name="inline_lang_choice"]'),i=a("#lang_"+e).html();l.val(i);var r=a("#default_cat_"+e).html();e==r&&l.prop("disabled",!0)}}})}(jQuery),function(a){a(document).ajaxSuccess(function(t,n,e){function l(t){var n=new Array;a(".translation_"+t).each(function(){n.push(a(this).parent().parent().attr("id").substring(4))});var e={action:"pll_update_term_rows",term_id:t,translations:n.join(","),taxonomy:a("input[name='taxonomy']").val(),post_type:a("input[name='post_type']").val(),screen:a("input[name='screen']").val(),_pll_nonce:a("#_pll_nonce").val()};a.post(ajaxurl,e,function(t){if(t){var n=wpAjax.parseAjaxResponse(t,"ajax-response");a.each(n.responses,function(){"row"==this.what&&a("#tag-"+this.supplemental.term_id).replaceWith(this.data)})}})}var i=wpAjax.unserialize(e.data);if("undefined"!=typeof i.action)switch(i.action){case"add-tag":res=wpAjax.parseAjaxResponse(n.responseXML,"ajax-response"),a.each(res.responses,function(){"term"==this.what&&l(this.supplemental.term_id)}),a(".htr_lang").val(0);break;case"delete-tag":l(i.tag_ID);break;case"inline-save-tax":l(i.tax_ID)}})}(jQuery),jQuery(document).ready(function(a){function t(){a(".tr_lang").each(function(){var t=a(this).attr("id").substring(8),n=a(this).parent().parent().siblings(".pll-edit-column");a(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_terms_not_translated&term_language="+a("#term_lang_choice").val()+"&term_id="+a("input[name='tag_ID']").val()+"&taxonomy="+a("input[name='taxonomy']").val()+"&translation_language="+t+"&post_type="+typenow+"&_pll_nonce="+a("#_pll_nonce").val(),select:function(e,l){a("#htr_lang_"+t).val(l.item.id),n.html(l.item.link)}}),a(this).blur(function(){a(this).val()||(a("#htr_lang_"+t).val(0),n.html(n.siblings(".hidden").children().clone()))})})}t(),a("#term_lang_choice").change(function(){var n=a(this).val(),e=a(this).children('option[value="'+n+'"]').attr("lang"),l=a('.pll-translation-column > span[lang="'+e+'"]').attr("dir"),i={action:"term_lang_choice",lang:n,from_tag:a("input[name='from_tag']").val(),term_id:a("input[name='tag_ID']").val(),taxonomy:a("input[name='taxonomy']").val(),post_type:typenow,_pll_nonce:a("#_pll_nonce").val()};a.post(ajaxurl,i,function(n){var e=wpAjax.parseAjaxResponse(n,"ajax-response");a.each(e.responses,function(){switch(this.what){case"translations":a("#term-translations").html(this.data),t();break;case"parent":a("#parent").replaceWith(this.data);break;case"tag_cloud":a(".tagcloud").replaceWith(this.data);break;case"flag":a(".pll-select-flag").html(this.data)}}),a("body").removeClass("pll-dir-rtl").removeClass("pll-dir-ltr").addClass("pll-dir-"+l)})})}); !function(a){a(document).bind("DOMNodeInserted",function(t){var n=a(t.target);if("inline-edit"==n.attr("id")){var e=n.prev().attr("id").replace("tag-","");if(e>0){var l=n.find(':input[name="inline_lang_choice"]'),i=a("#lang_"+e).html();l.val(i),e==a("#default_cat_"+e).html()&&l.prop("disabled",!0)}}})}(jQuery),function(a){a(document).ajaxSuccess(function(t,n,e){function l(t){var n=new Array;a(".translation_"+t).each(function(){n.push(a(this).parent().parent().attr("id").substring(4))});var e={action:"pll_update_term_rows",term_id:t,translations:n.join(","),taxonomy:a("input[name='taxonomy']").val(),post_type:a("input[name='post_type']").val(),screen:a("input[name='screen']").val(),_pll_nonce:a("#_pll_nonce").val()};a.post(ajaxurl,e,function(t){if(t){var n=wpAjax.parseAjaxResponse(t,"ajax-response");a.each(n.responses,function(){"row"==this.what&&a("#tag-"+this.supplemental.term_id).replaceWith(this.data)})}})}var i=wpAjax.unserialize(e.data);if(void 0!==i.action)switch(i.action){case"add-tag":res=wpAjax.parseAjaxResponse(n.responseXML,"ajax-response"),a.each(res.responses,function(){"term"==this.what&&l(this.supplemental.term_id)}),a(".htr_lang").val(0);break;case"delete-tag":l(i.tag_ID);break;case"inline-save-tax":l(i.tax_ID)}})}(jQuery),jQuery(document).ready(function(a){function t(){a(".tr_lang").each(function(){var t=a(this).attr("id").substring(8),n=a(this).parent().parent().siblings(".pll-edit-column");a(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_terms_not_translated&term_language="+a("#term_lang_choice").val()+"&term_id="+a("input[name='tag_ID']").val()+"&taxonomy="+a("input[name='taxonomy']").val()+"&translation_language="+t+"&post_type="+typenow+"&_pll_nonce="+a("#_pll_nonce").val(),select:function(e,l){a("#htr_lang_"+t).val(l.item.id),n.html(l.item.link)}}),a(this).blur(function(){a(this).val()||(a("#htr_lang_"+t).val(0),n.html(n.siblings(".hidden").children().clone()))})})}t(),a("#term_lang_choice").change(function(){var n=a(this).val(),e=a(this).children('option[value="'+n+'"]').attr("lang"),l=a('.pll-translation-column > span[lang="'+e+'"]').attr("dir"),i={action:"term_lang_choice",lang:n,from_tag:a("input[name='from_tag']").val(),term_id:a("input[name='tag_ID']").val(),taxonomy:a("input[name='taxonomy']").val(),post_type:typenow,_pll_nonce:a("#_pll_nonce").val()};a.post(ajaxurl,i,function(n){var e=wpAjax.parseAjaxResponse(n,"ajax-response");a.each(e.responses,function(){switch(this.what){case"translations":a("#term-translations").html(this.data),t();break;case"parent":a("#parent").replaceWith(this.data);break;case"tag_cloud":a(".tagcloud").replaceWith(this.data);break;case"flag":a(".pll-select-flag").html(this.data)}}),a("body").removeClass("pll-dir-rtl").removeClass("pll-dir-ltr").addClass("pll-dir-"+l)})})});
\ No newline at end of file
jQuery( document ).ready(function( $ ) { jQuery( document ).ready(
// biography function( $ ) {
// FIXME there is probably a more efficient way to do this // biography
var td = $( '#description' ).parent(); // FIXME there is probably a more efficient way to do this
var d = $( '#description' ).clone(); var td = $( '#description' ).parent();
var span = td.children( '.description' ).clone(); var d = $( '#description' ).clone();
td.children().remove(); var span = td.children( '.description' ).clone();
td.children().remove();
$( '.biography' ).each(function(){ $( '.biography' ).each(
lang = $( this ).attr( 'name' ).split( '___' ); function(){
desc = d.clone(); lang = $( this ).attr( 'name' ).split( '___' );
desc.attr( 'name', 'description_' + lang[0] ); desc = d.clone();
desc.html( $( this ).val() ); desc.attr( 'name', 'description_' + lang[0] );
td.append( '<div>' + lang[1] + '</div' ); desc.attr( 'id', 'description_' + lang[0] );
td.append( desc ); // Whitelist because description and lang value is already escaped by the side of PHP
}); desc.html( $( this ).val() ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
td.append( $( '<div></div>' ).text( lang[1] ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
td.append( desc ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
}
);
td.append( '<br />' ); td.append( '<br />' );
td.append( span ); // Whitelist because description come from html code generated by WordPress
}); td.append( span ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
}
);
jQuery(document).ready(function(e){var n=e("#description").parent(),d=e("#description").clone(),i=n.children(".description").clone();n.children().remove(),e(".biography").each(function(){lang=e(this).attr("name").split("___"),desc=d.clone(),desc.attr("name","description_"+lang[0]),desc.html(e(this).val()),n.append("<div>"+lang[1]+"</div"),n.append(desc)}),n.append("<br />"),n.append(i)}); jQuery(document).ready(function(e){var n=e("#description").parent(),d=e("#description").clone(),i=n.children(".description").clone();n.children().remove(),e(".biography").each(function(){lang=e(this).attr("name").split("___"),desc=d.clone(),desc.attr("name","description_"+lang[0]),desc.attr("id","description_"+lang[0]),desc.html(e(this).val()),n.append(e("<div></div>").text(lang[1])),n.append(desc)}),n.append("<br />"),n.append(i)});
\ No newline at end of file
jQuery( function( $ ) { jQuery(
var widgets_container, widgets_selector, flags; function( $ ) {
var widgets_container, widgets_selector, flags;
if ( 'undefined' !== typeof pll_widgets && pll_widgets.hasOwnProperty( 'flags' ) ) { if ( 'undefined' !== typeof pll_widgets && pll_widgets.hasOwnProperty( 'flags' ) ) {
flags = pll_widgets.flags; flags = pll_widgets.flags;
}
/**
* Prepend widget titles with a flag once a language is selected.
* @param {object} widget The widget element.
* @return {void} Nothing.
*/
function add_flag( widget ) {
if ( ! flags ) {
return;
} }
widget = $( widget );
var title = $( '.widget-top .widget-title h3', widget ),
locale = $( '.pll-lang-choice option:selected', widget ).val(),
icon = ( locale && flags.hasOwnProperty( locale ) ) ? flags[ locale ] : null;
if ( icon ) {
icon += ' &nbsp; ';
var current = $( '.pll-lang', title );
if ( current.length ) {
current.html( icon );
} else {
flag = '<span class="pll-lang">' + icon + '</span>';
title.prepend( flag );
}
} else {
$( '.pll-lang', title ).remove();
}
}
if ( 'undefined' !== typeof wp.customize ) {
widgets_container = $( '#customize-controls' );
widgets_selector = '.customize-control .widget';
/** /**
* WP Customizer add control listener. * Prepend widget titles with a flag once a language is selected.
* *
* @link https://wordpress.stackexchange.com/questions/256536/callback-after-wordpress-customizer-complete-loading * @param {object} widget The widget element.
*
* @param {object} control The control type.
* @return {void} Nothing. * @return {void} Nothing.
*/ */
function customize_add_flag( control ) { function add_flag( widget ) {
if ( ! control.extended( wp.customize.Widgets.WidgetControl ) ) { if ( ! flags ) {
return; return;
} }
widget = $( widget );
var title = $( '.widget-top .widget-title h3', widget ),
locale = $( '.pll-lang-choice option:selected', widget ).val(),
// Icon is HTML built and come from server side and is well escaped when necessary
icon = ( locale && flags.hasOwnProperty( locale ) ) ? flags[ locale ] : null;
/* if ( icon ) {
* Make sure the widget's contents are embedded; normally this is done icon += ' &nbsp; ';
* when the control is expanded, for DOM performance reasons. var current = $( '.pll-lang', title );
if ( current.length ) {
current.html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
} else {
flag = $( '<span />' ).addClass( 'pll-lang' ).html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
title.prepend( flag );
}
} else {
$( '.pll-lang', title ).remove();
}
}
if ( 'undefined' !== typeof wp.customize ) {
widgets_container = $( '#customize-controls' );
widgets_selector = '.customize-control .widget';
/**
* WP Customizer add control listener.
*
* @link https://wordpress.stackexchange.com/questions/256536/callback-after-wordpress-customizer-complete-loading
*
* @param {object} control The control type.
* @return {void} Nothing.
*/ */
control.embedWidgetContent(); function customize_add_flag( control ) {
if ( ! control.extended( wp.customize.Widgets.WidgetControl ) ) {
return;
}
// Now we know for sure the widget is fully embedded. /*
add_flag( control.container.find( '.widget' ) ); * Make sure the widget's contents are embedded; normally this is done
} * when the control is expanded, for DOM performance reasons.
wp.customize.control.each( customize_add_flag ); */
wp.customize.control.bind( 'add', customize_add_flag ); control.embedWidgetContent();
// Now we know for sure the widget is fully embedded.
add_flag( control.container.find( '.widget' ) );
}
wp.customize.control.each( customize_add_flag );
wp.customize.control.bind( 'add', customize_add_flag );
} else { } else {
widgets_container = $( '#widgets-right' ); widgets_container = $( '#widgets-right' );
widgets_selector = '.widget'; widgets_selector = '.widget';
} }
// Add flags on load. // Add flags on load.
$( widgets_selector, widgets_container ).each( function() { $( widgets_selector, widgets_container ).each(
add_flag( this ); function() {
} ); add_flag( this );
}
);
// Update flags. // Update flags.
widgets_container.on( 'change', '.pll-lang-choice', function() { widgets_container.on(
add_flag( $( this ).parents( '.widget' ) ); 'change',
} ); '.pll-lang-choice',
function() {
add_flag( $( this ).parents( '.widget' ) );
}
);
} ); }
);
jQuery(function(e){function t(t){if(o){t=e(t);var n=e(".widget-top .widget-title h3",t),l=e(".pll-lang-choice option:selected",t).val(),i=l&&o.hasOwnProperty(l)?o[l]:null;if(i){i+=" &nbsp; ";var d=e(".pll-lang",n);d.length?d.html(i):(flag='<span class="pll-lang">'+i+"</span>",n.prepend(flag))}else e(".pll-lang",n).remove()}}function n(e){e.extended(wp.customize.Widgets.WidgetControl)&&(e.embedWidgetContent(),t(e.container.find(".widget")))}var l,i,o;"undefined"!=typeof pll_widgets&&pll_widgets.hasOwnProperty("flags")&&(o=pll_widgets.flags),"undefined"!=typeof wp.customize?(l=e("#customize-controls"),i=".customize-control .widget",wp.customize.control.each(n),wp.customize.control.bind("add",n)):(l=e("#widgets-right"),i=".widget"),e(i,l).each(function(){t(this)}),l.on("change",".pll-lang-choice",function(){t(e(this).parents(".widget"))})}); jQuery(function(e){var t,l,n;function i(t){if(n){t=e(t);var l=e(".widget-top .widget-title h3",t),i=e(".pll-lang-choice option:selected",t).val(),o=i&&n.hasOwnProperty(i)?n[i]:null;if(o){o+=" &nbsp; ";var d=e(".pll-lang",l);d.length?d.html(o):(flag=e("<span />").addClass("pll-lang").html(o),l.prepend(flag))}else e(".pll-lang",l).remove()}}if("undefined"!=typeof pll_widgets&&pll_widgets.hasOwnProperty("flags")&&(n=pll_widgets.flags),void 0!==wp.customize){function o(e){e.extended(wp.customize.Widgets.WidgetControl)&&(e.embedWidgetContent(),i(e.container.find(".widget")))}t=e("#customize-controls"),l=".customize-control .widget",wp.customize.control.each(o),wp.customize.control.bind("add",o)}else t=e("#widgets-right"),l=".widget";e(l,t).each(function(){i(this)}),t.on("change",".pll-lang-choice",function(){i(e(this).parents(".widget"))})});
\ No newline at end of file
...@@ -14,8 +14,6 @@ class PLL_Lingotek { ...@@ -14,8 +14,6 @@ class PLL_Lingotek {
* @since 1.7.7 * @since 1.7.7
*/ */
public function init() { public function init() {
$options = get_option( 'polylang' );
// The Lingotek tab // The Lingotek tab
add_filter( 'pll_settings_tabs', array( $this, 'add_tab' ) ); add_filter( 'pll_settings_tabs', array( $this, 'add_tab' ) );
add_action( 'pll_settings_active_tab_lingotek', array( $this, 'display_tab' ) ); add_action( 'pll_settings_active_tab_lingotek', array( $this, 'display_tab' ) );
...@@ -30,7 +28,7 @@ class PLL_Lingotek { ...@@ -30,7 +28,7 @@ class PLL_Lingotek {
$content = __( 'You’ve just upgraded to the latest version of Polylang! Would you like to automatically translate your website for free?', 'polylang' ); $content = __( 'You’ve just upgraded to the latest version of Polylang! Would you like to automatically translate your website for free?', 'polylang' );
$buttons = sprintf( $buttons = sprintf(
'<a href="%s" class="button button-primary" style="margin-right: 10px">%s</a>', '<a href="%s" class="button button-primary">%s</a>',
admin_url( 'admin.php?page=mlang_lingotek' ), admin_url( 'admin.php?page=mlang_lingotek' ),
__( 'Learn more', 'polylang' ) __( 'Learn more', 'polylang' )
); );
...@@ -39,7 +37,7 @@ class PLL_Lingotek { ...@@ -39,7 +37,7 @@ class PLL_Lingotek {
$content .= ' ' . __( 'Click on Activate Lingotek to start translating.', 'polylang' ); $content .= ' ' . __( 'Click on Activate Lingotek to start translating.', 'polylang' );
$buttons = sprintf( $buttons = sprintf(
'<a href="%s" class="button button-primary" style="margin-right: 10px">%s</a>', '<a href="%s" class="button button-primary">%s</a>',
$link, $link,
__( 'Activate Lingotek', 'polylang' ) __( 'Activate Lingotek', 'polylang' )
) . $buttons; ) . $buttons;
......
...@@ -61,7 +61,7 @@ class PLL_Featured_Content { ...@@ -61,7 +61,7 @@ class PLL_Featured_Content {
$settings = Featured_Content::get_setting(); $settings = Featured_Content::get_setting();
if ( ! $term = wpcom_vip_get_term_by( 'name', $settings['tag-name'], 'post_tag' ) ) { if ( ! $term = get_term_by( 'name', $settings['tag-name'], 'post_tag' ) ) {
return $featured_ids; return $featured_ids;
} }
......
...@@ -266,10 +266,18 @@ class PLL_Plugins_Compat { ...@@ -266,10 +266,18 @@ class PLL_Plugins_Compat {
* @since 2.0.10 * @since 2.0.10
*/ */
public function twenty_seventeen_init() { public function twenty_seventeen_init() {
if ( 'twentyseventeen' === get_template() && function_exists( 'twentyseventeen_panel_count' ) && did_action( 'pll_init' ) && PLL() instanceof PLL_Frontend ) { if ( 'twentyseventeen' === get_template() && did_action( 'pll_init' ) ) {
$num_sections = twentyseventeen_panel_count(); if ( function_exists( 'twentyseventeen_panel_count' ) && PLL() instanceof PLL_Frontend ) {
for ( $i = 1; $i < ( 1 + $num_sections ); $i++ ) { $num_sections = twentyseventeen_panel_count();
add_filter( 'theme_mod_panel_' . $i, 'pll_get_post' ); for ( $i = 1; $i < ( 1 + $num_sections ); $i++ ) {
add_filter( 'theme_mod_panel_' . $i, 'pll_get_post' );
}
}
if ( PLL() instanceof PLL_Frontend ) {
add_filter( 'theme_mod_external_header_video', 'pll__' );
} else {
pll_register_string( __( 'Header video', 'polylang' ), get_theme_mod( 'external_header_video' ), 'Twenty Seventeen', false );
} }
} }
} }
......
...@@ -113,6 +113,8 @@ class PLL_WP_Import extends WP_Import { ...@@ -113,6 +113,8 @@ class PLL_WP_Import extends WP_Import {
protected function remap_terms_relations( &$terms ) { protected function remap_terms_relations( &$terms ) {
global $wpdb; global $wpdb;
$trs = array();
foreach ( $terms as $term ) { foreach ( $terms as $term ) {
$translations = maybe_unserialize( $term['term_description'] ); $translations = maybe_unserialize( $term['term_description'] );
foreach ( $translations as $slug => $old_id ) { foreach ( $translations as $slug => $old_id ) {
...@@ -161,6 +163,8 @@ class PLL_WP_Import extends WP_Import { ...@@ -161,6 +163,8 @@ class PLL_WP_Import extends WP_Import {
protected function remap_translations( &$terms, &$processed_objects ) { protected function remap_translations( &$terms, &$processed_objects ) {
global $wpdb; global $wpdb;
$u = array();
foreach ( $terms as $term ) { foreach ( $terms as $term ) {
$translations = maybe_unserialize( $term['term_description'] ); $translations = maybe_unserialize( $term['term_description'] );
$new_translations = array(); $new_translations = array();
......
...@@ -189,7 +189,7 @@ class PLL_Admin_Sync extends PLL_Sync { ...@@ -189,7 +189,7 @@ class PLL_Admin_Sync extends PLL_Sync {
if ( is_object( $this->$obj ) && method_exists( $this->$obj, 'copy' ) ) { if ( is_object( $this->$obj ) && method_exists( $this->$obj, 'copy' ) ) {
if ( WP_DEBUG ) { if ( WP_DEBUG ) {
$debug = debug_backtrace(); // phpcs:ignore WordPress.PHP.DevelopmentFunctions $debug = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
$i = 1 + empty( $debug[1]['line'] ); // The file and line are in $debug[2] if the function was called using call_user_func $i = 1 + empty( $debug[1]['line'] ); // The file and line are in $debug[2] if the function was called using call_user_func
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions
...@@ -205,7 +205,7 @@ class PLL_Admin_Sync extends PLL_Sync { ...@@ -205,7 +205,7 @@ class PLL_Admin_Sync extends PLL_Sync {
return call_user_func_array( array( $this->$obj, 'copy' ), $args ); return call_user_func_array( array( $this->$obj, 'copy' ), $args );
} }
$debug = debug_backtrace(); // phpcs:ignore WordPress.PHP.DevelopmentFunctions $debug = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions
sprintf( sprintf(
'Call to undefined function PLL()->sync->%1$s() in %2$s on line %3$s' . "\nError handler", 'Call to undefined function PLL()->sync->%1$s() in %2$s on line %3$s' . "\nError handler",
......
...@@ -65,7 +65,7 @@ class PLL_Settings_Sync extends PLL_Settings_Module { ...@@ -65,7 +65,7 @@ class PLL_Settings_Sync extends PLL_Settings_Module {
* @param array $options * @param array $options
*/ */
protected function update( $options ) { protected function update( $options ) {
$newoptions['sync'] = empty( $options['sync'] ) ? array() : array_keys( $options['sync'], 1 ); $newoptions = array( 'sync' => empty( $options['sync'] ) ? array() : array_keys( $options['sync'], 1 ) );
return $newoptions; // take care to return only validated options return $newoptions; // take care to return only validated options
} }
......
...@@ -359,8 +359,6 @@ abstract class PLL_Sync_Metas { ...@@ -359,8 +359,6 @@ abstract class PLL_Sync_Metas {
* @param array $translations The list of translations object ids * @param array $translations The list of translations object ids
*/ */
public function save_object( $object_id, $obj, $translations ) { public function save_object( $object_id, $obj, $translations ) {
$src_lang = array_search( $object_id, $translations );
foreach ( $translations as $tr_lang => $tr_id ) { foreach ( $translations as $tr_lang => $tr_id ) {
if ( $tr_id != $object_id ) { if ( $tr_id != $object_id ) {
$this->copy( $object_id, $tr_id, $tr_lang, true ); $this->copy( $object_id, $tr_id, $tr_lang, true );
......
...@@ -83,7 +83,6 @@ class PLL_Sync { ...@@ -83,7 +83,6 @@ class PLL_Sync {
public function can_sync_post_parent( $post_parent, $post_id, $postarr ) { public function can_sync_post_parent( $post_parent, $post_id, $postarr ) {
if ( ! empty( $postarr['ID'] ) && ! $this->model->post->current_user_can_synchronize( $postarr['ID'] ) ) { if ( ! empty( $postarr['ID'] ) && ! $this->model->post->current_user_can_synchronize( $postarr['ID'] ) ) {
$tr_ids = $this->model->post->get_translations( $postarr['ID'] ); $tr_ids = $this->model->post->get_translations( $postarr['ID'] );
$orig_lang = array_search( $postarr['ID'], $tr_ids );
foreach ( $tr_ids as $tr_id ) { foreach ( $tr_ids as $tr_id ) {
if ( $tr_id !== $postarr['ID'] && $post = get_post( $tr_id ) ) { if ( $tr_id !== $postarr['ID'] && $post = get_post( $tr_id ) ) {
$post_parent = $post->post_parent; $post_parent = $post->post_parent;
......
This diff is collapsed.
This diff is collapsed.
<?php
/**
* Displays the wizard notice content
*
* @since 2.7
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Don't access directly.
};
$wizard_url = add_query_arg(
array(
'page' => 'mlang_wizard',
),
admin_url( 'admin.php' )
);
?>
<p>
<strong>
<?php
printf(
/* translators: %s is the plugin name */
esc_html__( 'Welcome to %s', 'polylang' ),
esc_html( POLYLANG )
);
?>
</strong>
<?php
echo ' &#8211; ';
esc_html_e( 'You&lsquo;re almost ready to translate your contents!', 'polylang' );
?>
</p>
<p class="buttons">
<a
href="<?php echo esc_url( $wizard_url ); ?>"
class="button button-primary"
>
<?php esc_html_e( 'Run the Setup Wizard', 'polylang' ); ?>
</a>
<a
class="button button-secondary skip"
href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'pll-hide-notice', 'wizard' ), 'wizard', '_pll_notice_nonce' ) ); ?>"
>
<?php esc_html_e( 'Skip setup', 'polylang' ); ?>
</a>
</p>
jQuery( document ).ready(
function( $ ) {
var addLanguageForm = $( '.languages-step' ); // Form element.
var languageFields = $( '#language-fields' ); // Element where to append hidden fields for creating language.
var languagesTable = $( '#languages' ); // Table element contains languages list to create.
var languagesListTable = $( '#languages tbody' ); // Table rows with languages list to create.
var definedLanguagesListTable = $( '#defined-languages tbody' ); // Table rows with already defined languages list.
var languagesList = $( '#lang_list' ); // Select form element with predefined languages without already created languages.
var nextStepButton = $( '[name="save_step"]' ); // The button for continuing to the next step.
var messagesContainer = $( '#messages' ); // Element where to display error messages.
var languagesMap = new Map(); // Languages map object for managing the languages to create.
var dialog = $( '#dialog' ); // Dialog box for alerting the language selected has not been added to the list.
/**
* Add a language in the list to create it in Polylang settings
*
* @param {object} language The language object
*/
function addLanguage( language ) {
// language properties come from the select dropdown which is built server side and well escaped.
var languageValueHtml = $( '<td />' ).text( language.text ).prepend( language.flagUrl );
var languageTrashIconHtml = $( '<td />' )
.append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
$( '<span />' )
.addClass( 'dashicons dashicons-trash' )
.attr( 'data-language', language.locale )
.append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
$( '<span />' )
.addClass( 'screen-reader-text' )
.text( pll_wizard_params.i18n_remove_language_icon )
)
);
var languageLineHtml = $( '<tr />' ).prepend( languageTrashIconHtml ).prepend( languageValueHtml );
var languageFieldHtml = $( '<input />' ).attr(
{
type: 'hidden',
name: 'languages[]'
}
).val( language.locale );
languagesList.val( '' );
languagesList.selectmenu( 'refresh' ); // Refresh jQuery selectmenu widget after changing the value.
languagesMap.set( language.locale, language );
// see above how languageLineHtml is built.
languagesListTable.append( languageLineHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
// Bind click event on trash icon.
languagesListTable.on(
'click',
'span[data-language=' + language.locale + ']',
function( event ) {
event.preventDefault();
// Remove line in languages table.
$( this ).parents( 'tr' ).remove();
// Remove input field.
languageField = languageFields.children( 'input[value=' + $( this ).data( 'language' ) + ']' ).remove();
// If there is no more languages hide languages table.
if ( languagesListTable.children().length <= 0 ) {
languagesTable.hide();
}
// Remove language from the Map.
languagesMap.delete( $( this ).data( 'language' ) );
// Hide error message.
hideError();
}
);
// see above how languageFieldHtml is built.
// Add hidden input field for posting the form.
languageFields.append( languageFieldHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
}
/**
* Display an error message
*
* @param {string} message The message to display
*/
function showError( message ) {
messagesContainer.empty();
messagesContainer.prepend( $( '<p/>' ).addClass( 'error' ).text( message ) );
}
/**
* Hide all error messages and fields in error
*/
function hideError() {
messagesContainer.empty();
addLanguageForm.find( '.error' ).removeClass( 'error field-in-error' );
}
/**
* Style the field to indicate where the error is
*
* @param {object} field The jQuery element which is in error
*/
function showFieldInError( field ) {
field.addClass( 'error field-in-error' );
}
/**
* Focus on a specific element
*
* @param {object} field The jQuery element which will be focused
*/
function focusOnField( field ) {
field.focus();
}
/**
* Disable a specific button
*
* @param {object} button
*/
function disableButton( button ){
button.prop( 'disabled', true );
// Because the button is disabled we need to add the value of the button to ensure it will pass in the request.
addLanguageForm.append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
$( '<input />' ).prop(
{
type: 'hidden',
name: button.prop( 'name' ),
value: button.prop( 'value' )
}
)
);
}
/**
* Remove error when a new selection is done in languages list.
*/
languagesList.on(
'selectmenuchange',
function() {
hideError();;
}
);
/**
* Bind click event on "Add language" button
*/
$( '#add-language' ).on(
'click',
function( event ) {
hideError();
var selectedOption = event.currentTarget.form.lang_list.options[event.currentTarget.form.lang_list.selectedIndex];
if ( '' !== selectedOption.value && ! languagesMap.has( selectedOption.value ) ) {
addLanguage(
{
locale: selectedOption.value,
text: selectedOption.innerText,
name: $( selectedOption ).data( 'language-name' ),
flagUrl: $( selectedOption ).data( 'flag-html' )
}
);
// Show table of languages.
languagesTable.show();
// Put back the focus on the select language field after clicking on "Add language button".
focusOnField( $( '#lang_list-button' ) );
} else {
var message = pll_wizard_params.i18n_no_language_selected;
if ( languagesMap.has( selectedOption.value ) ) {
message = pll_wizard_params.i18n_language_already_added;
}
showError( message );
showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
focusOnField( $( '#lang_list-button' ) );
}
}
);
/**
* Bind submit event on "add_lang" form
*/
addLanguageForm.on(
'submit',
function( event ) {
// Verify if there is at least one language.
var isLanguagesAlreadyDefined = definedLanguagesListTable.children().length > 0;
var selectedLanguage = $( '#lang_list' ).val();
if ( languagesMap.size <= 0 && ! isLanguagesAlreadyDefined ) {
if ( '' === selectedLanguage ) {
showError( pll_wizard_params.i18n_no_language_added );
showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
focusOnField( $( '#lang_list-button' ) );
} else {
showError( pll_wizard_params.i18n_add_language_needed );
showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
focusOnField( $( '#add-language' ) ); // Put the focus on the "Add language" button.
}
return false;
}
// Verify if the language has been added in the list otherwise display a dialog box to confirm what to do.
if ( '' !== selectedLanguage ) {
// Verify we don't add a duplicate language before opening the dialog box otherwise display an error message.
if ( ! languagesMap.has( selectedLanguage ) ) {
dialog.dialog( 'open' );
} else {
showError( pll_wizard_params.i18n_language_already_added );
showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
focusOnField( $( '#lang_list-button' ) );
}
return false;
}
disableButton( nextStepButton );
}
);
// Is there an error return by PHP ?
var searchParams = new URLSearchParams( document.location.search );
if ( searchParams.has( 'activate_error' ) ) {
// If the error code exists, display it.
if ( undefined !== pll_wizard_params[ searchParams.get( 'activate_error' ) ] ) {
showError( pll_wizard_params[ searchParams.get( 'activate_error' ) ] );
}
}
function confirmDialog( what ) {
switch ( what ) {
case 'yes':
var selectedOption = $( '#lang_list' ).children( ':selected' );
addLanguage(
{
locale: selectedOption[0].value,
text: selectedOption[0].innerText,
name: $( selectedOption ).data( 'language-name' ),
flagUrl: $( selectedOption ).data( 'flag-html' )
}
);
break;
case 'no':
// Empty select form field and submit again the form.
languagesList.val( '' );
break;
case 'ignore':
}
dialog.dialog( 'close' );
if ( 'ignore' === what ) {
focusOnField( $( '#lang_list-button' ) );
} else {
addLanguageForm.submit();
}
}
// Initialize dialog box in the case a langauge is selected but not added in the list.
dialog.dialog(
{
autoOpen: false,
modal: true,
draggable: false,
resizable: false,
title: pll_wizard_params.i18n_dialog_title,
minWidth: 600,
maxWidth: '100%',
open: function( event, ui ) {
// Change dialog box position for rtl language
if ( $( 'body' ).hasClass( 'rtl' ) ) {
$( this ).parent().css(
{
right: $( this ).parent().css( 'left' ),
left: 'auto'
}
);
}
// Display language name and flag information in dialog box.
$( this ).find( '#dialog-language' ).text( $( '#lang_list' ).children( ':selected' )[0].innerText );
$( this ).find( '#dialog-language-flag' ).empty().prepend( $( '#lang_list' ).children( ':selected' ).data( 'flag-html' ) );
},
buttons: [
{
text: pll_wizard_params.i18n_dialog_yes_button,
click: function( event ) {
confirmDialog( 'yes' );
}
},
{
text: pll_wizard_params.i18n_dialog_no_button,
click: function( event ) {
confirmDialog( 'no' );
}
},
{
text: pll_wizard_params.i18n_dialog_ignore_button,
click: function( event ) {
confirmDialog( 'ignore' );
}
}
]
}
)
}
);
jQuery(document).ready(function(a){var e=a(".languages-step"),n=a("#language-fields"),t=a("#languages"),l=a("#languages tbody"),i=a("#defined-languages tbody"),r=a("#lang_list"),d=a('[name="save_step"]'),s=a("#messages"),o=new Map,g=a("#dialog");function u(e){var i=a("<td />").text(e.text).prepend(e.flagUrl),d=a("<td />").append(a("<span />").addClass("dashicons dashicons-trash").attr("data-language",e.locale).append(a("<span />").addClass("screen-reader-text").text(pll_wizard_params.i18n_remove_language_icon))),s=a("<tr />").prepend(d).prepend(i),g=a("<input />").attr({type:"hidden",name:"languages[]"}).val(e.locale);r.val(""),r.selectmenu("refresh"),o.set(e.locale,e),l.append(s),l.on("click","span[data-language="+e.locale+"]",function(e){e.preventDefault(),a(this).parents("tr").remove(),languageField=n.children("input[value="+a(this).data("language")+"]").remove(),l.children().length<=0&&t.hide(),o.delete(a(this).data("language")),c()}),n.append(g)}function p(e){s.empty(),s.prepend(a("<p/>").addClass("error").text(e))}function c(){s.empty(),e.find(".error").removeClass("error field-in-error")}function _(a){a.addClass("error field-in-error")}function m(a){a.focus()}r.on("selectmenuchange",function(){c()}),a("#add-language").on("click",function(e){c();var n=e.currentTarget.form.lang_list.options[e.currentTarget.form.lang_list.selectedIndex];if(""===n.value||o.has(n.value)){var l=pll_wizard_params.i18n_no_language_selected;o.has(n.value)&&(l=pll_wizard_params.i18n_language_already_added),p(l),_(r.next("span.ui-selectmenu-button")),m(a("#lang_list-button"))}else u({locale:n.value,text:n.innerText,name:a(n).data("language-name"),flagUrl:a(n).data("flag-html")}),t.show(),m(a("#lang_list-button"))}),e.on("submit",function(n){var t,l=i.children().length>0,s=a("#lang_list").val();return o.size<=0&&!l?(""===s?(p(pll_wizard_params.i18n_no_language_added),_(r.next("span.ui-selectmenu-button")),m(a("#lang_list-button"))):(p(pll_wizard_params.i18n_add_language_needed),_(r.next("span.ui-selectmenu-button")),m(a("#add-language"))),!1):""!==s?(o.has(s)?(p(pll_wizard_params.i18n_language_already_added),_(r.next("span.ui-selectmenu-button")),m(a("#lang_list-button"))):g.dialog("open"),!1):((t=d).prop("disabled",!0),void e.append(a("<input />").prop({type:"hidden",name:t.prop("name"),value:t.prop("value")})))});var h=new URLSearchParams(document.location.search);function f(n){switch(n){case"yes":var t=a("#lang_list").children(":selected");u({locale:t[0].value,text:t[0].innerText,name:a(t).data("language-name"),flagUrl:a(t).data("flag-html")});break;case"no":r.val("")}g.dialog("close"),"ignore"===n?m(a("#lang_list-button")):e.submit()}h.has("activate_error")&&void 0!==pll_wizard_params[h.get("activate_error")]&&p(pll_wizard_params[h.get("activate_error")]),g.dialog({autoOpen:!1,modal:!0,draggable:!1,resizable:!1,title:pll_wizard_params.i18n_dialog_title,minWidth:600,maxWidth:"100%",open:function(e,n){a("body").hasClass("rtl")&&a(this).parent().css({right:a(this).parent().css("left"),left:"auto"}),a(this).find("#dialog-language").text(a("#lang_list").children(":selected")[0].innerText),a(this).find("#dialog-language-flag").empty().prepend(a("#lang_list").children(":selected").data("flag-html"))},buttons:[{text:pll_wizard_params.i18n_dialog_yes_button,click:function(a){f("yes")}},{text:pll_wizard_params.i18n_dialog_no_button,click:function(a){f("no")}},{text:pll_wizard_params.i18n_dialog_ignore_button,click:function(a){f("ignore")}}]})});
<?php
/**
* Displays the wizard
*
* @since 2.7
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Don't access directly.
};
$admin_body_class = array( 'pll-wizard', 'wp-core-ui' );
if ( is_rtl() ) {
$admin_body_class[] = 'rtl';
}
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>
<?php
printf(
/* translators: %s is the plugin name */
esc_html__( '%s &rsaquo; Setup', 'polylang' ),
esc_html( POLYLANG )
);
?>
</title>
<script type="text/javascript">
var ajaxurl = '<?php echo esc_url( admin_url( 'admin-ajax.php', 'relative' ) ); ?>';
</script>
<?php do_action( 'admin_enqueue_scripts' ); ?>
<?php wp_print_scripts( $this->steps[ $this->step ]['scripts'] ); ?>
<?php wp_print_styles( array_merge( $this->styles, $this->steps[ $this->step ]['styles'] ) ); ?>
<?php do_action( 'admin_head' ); ?>
</head>
<body class="<?php echo join( ' ', array_map( 'sanitize_key', $admin_body_class ) ); ?>">
<h1 id="pll-logo">
<a href="https://polylang.pro/" class="title">
<span><img src="<?php echo esc_url( plugins_url( '/modules/wizard/images/polylang-logo.png', POLYLANG_FILE ) ); ?>" /></span>
<?php echo esc_html( POLYLANG ); ?>
</a>
</h1>
<ol class="pll-wizard-steps">
<?php
foreach ( $this->steps as $step_key => $step ) {
$is_completed = array_search( $this->step, array_keys( $this->steps ), true ) > array_search( $step_key, array_keys( $this->steps ), true );
if ( $step_key === $this->step ) {
?>
<li class="active"><?php echo esc_html( $step['name'] ); ?></li>
<?php
} elseif ( $is_completed ) {
?>
<li class="done">
<a
href="<?php echo esc_url( add_query_arg( 'step', $step_key, remove_query_arg( 'activate_error' ) ) ); ?>"
>
<?php echo esc_html( $step['name'] ); ?>
</a>
</li>
<?php
} else {
?>
<li><?php echo esc_html( $step['name'] ); ?></li>
<?php
}
}
?>
</ol>
<div class="pll-wizard-content">
<form method="post" class="<?php echo esc_attr( "{$this->step}-step" ); ?>">
<?php
wp_nonce_field( 'pll-wizard', '_pll_nonce' );
if ( ! empty( $this->steps[ $this->step ]['view'] ) ) {
call_user_func( $this->steps[ $this->step ]['view'], $this );
}
?>
<?php if ( 'last' !== $this->step ) : ?>
<p class="pll-wizard-actions step">
<button
type="submit"
class="button-primary button button-large button-next"
value="continue"
name="save_step"
>
<?php esc_html_e( 'Continue', 'polylang' ); ?><span class="dashicons dashicons-arrow-right-alt2"></span>
</button>
</p>
<?php endif; ?>
</form>
</div>
<div class="pll-wizard-footer">
<?php if ( 'last' !== $this->step ) : ?>
<a
class="pll-wizard-footer-links"
href="<?php echo esc_url( admin_url() ); ?>"
>
<?php esc_html_e( 'Not right now', 'polylang' ); ?>
</a>
<?php endif; ?>
</div>
</body>
</html>
<?php
/**
* Displays the wizard home page step
*
* @since 2.7
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Don't access directly.
};
$languages = $this->model->get_languages_list();
$default_language = count( $languages ) > 0 ? $this->options['default_lang'] : null;
$home_page_id = get_option( 'page_on_front' );
$translations = $this->model->post->get_translations( $home_page_id );
$untranslated_languages = array();
$home_page = $home_page_id > 0 ? get_post( $home_page_id ) : null;
$home_page_language = $this->model->post->get_language( $home_page_id );
foreach ( $languages as $language ) {
if ( ! $this->model->post->get( $home_page_id, $language ) ) {
$untranslated_languages[] = $language;
}
}
?>
<input type="hidden" name="home_page" value="<?php echo esc_attr( $home_page->ID ); ?>" />
<input type="hidden" name="home_page_title" value="<?php echo esc_attr( $home_page->post_title ); ?>" />
<?php if ( false !== $home_page_language ) : ?>
<input type="hidden" name="home_page_language" value="<?php echo esc_attr( $home_page_language->slug ); ?>" />
<?php endif; ?>
<h2><?php esc_html_e( 'Homepage', 'polylang' ); ?></h2>
<p>
<?php
printf(
/* translators: %s is the post title of the front page */
esc_html__( 'You defined this page as your static homepage: %s.', 'polylang' ),
'<strong>' . esc_html( $home_page->post_title ) . '</strong>'
);
?>
<br />
<?php
printf(
/* translators: %s is the language of the front page ( flag, native name and locale ) */
esc_html__( 'Its language is : %s.', 'polylang' ),
$home_page_language->flag . ' <strong>' . esc_html( $home_page_language->name ) . ' ' . esc_html( $home_page_language->locale ) . '</strong>' //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
)
?>
<br />
<?php esc_html_e( 'For your site to work correctly, this page must be translated in all available languages.', 'polylang' ); ?>
</p>
<p>
<?php esc_html_e( 'After the pages is created, it is up to you to put the translated content in each page linked to each language.', 'polylang' ); ?>
</p>
<?php if ( $translations ) : ?>
<table id="translated-languages" class="striped">
<thead>
<tr>
<th><?php esc_html_e( 'Your static homepage is already translated in', 'polylang' ); ?></th>
</tr>
</thead>
<tbody>
<?php
foreach ( array_keys( $translations ) as $lang ) {
$language = $this->model->get_language( $lang );
?>
<tr>
<td>
<?php
echo $language->flag; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo ' ' . esc_html( $language->name ) . ' ' . esc_html( $language->locale ) . ' ';
?>
<?php if ( $language->slug === $default_language ) : ?>
<span class="icon-default-lang">
<span class="screen-reader-text">
<?php esc_html_e( 'Default language', 'polylang' ); ?>
</span>
</span>
<?php endif; ?>
<input type="hidden" name="translated_languages[]" value="<?php echo esc_attr( $language->slug ); ?>" />
</td>
</tr>
<?php
}
?>
</tbody>
</table>
<?php endif; ?>
<table id="untranslated-languages" class="striped">
<?php if ( ! is_null( $default_language ) ) : ?>
<caption><span class="icon-default-lang"></span> <?php esc_html_e( 'Default language', 'polylang' ); ?></caption>
<?php endif; ?>
<thead>
<?php if ( count( $untranslated_languages ) >= 1 ) : ?>
<tr>
<th><?php esc_html_e( 'We are going to prepare this page in', 'polylang' ); ?></th>
</tr>
<?php elseif ( false !== $home_page_language && count( $untranslated_languages ) <= 0 ) : ?>
<tr>
<th>
<span class="dashicons dashicons-info"></span>
<?php esc_html_e( 'One language is well defined and assigned to your home page.', 'polylang' ); ?>
</th>
</tr>
<tr>
<td><?php esc_html_e( "If you add a new language, don't forget to translate your homepage.", 'polylang' ); ?></td>
</tr>
<?php endif; ?>
</thead>
<tbody>
<?php
foreach ( $untranslated_languages as $lg ) {
?>
<tr>
<td>
<?php
echo $lg->flag; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo ' ' . esc_html( $lg->name ) . ' ' . esc_html( $lg->locale ) . ' ';
?>
<?php if ( $lg->slug === $default_language ) : ?>
<span class="icon-default-lang">
<span class="screen-reader-text">
<?php esc_html_e( 'Default language', 'polylang' ); ?>
</span>
</span>
<?php endif; ?>
<input type="hidden" name="untranslated_languages[]" value="<?php echo esc_attr( $lg->slug ); ?>" />
</td>
</tr>
<?php
}
?>
</tbody>
</table>
This diff is collapsed.
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
/** /**
Plugin Name: Polylang Plugin Name: Polylang
Plugin URI: https://polylang.pro Plugin URI: https://polylang.pro
Version: 2.6.10 Version: 2.7.1
Author: WP SYNTEX Author: WP SYNTEX
Author uri: https://polylang.pro Author uri: https://polylang.pro
Description: Adds multilingual capability to WordPress Description: Adds multilingual capability to WordPress
...@@ -51,8 +51,8 @@ if ( defined( 'POLYLANG_BASENAME' ) ) { ...@@ -51,8 +51,8 @@ if ( defined( 'POLYLANG_BASENAME' ) ) {
} }
} else { } else {
// Go on loading the plugin // Go on loading the plugin
define( 'POLYLANG_VERSION', '2.6.10' ); define( 'POLYLANG_VERSION', '2.7.1' );
define( 'PLL_MIN_WP_VERSION', '4.7' ); define( 'PLL_MIN_WP_VERSION', '4.9' );
define( 'PLL_MIN_PHP_VERSION', '5.6' ); define( 'PLL_MIN_PHP_VERSION', '5.6' );
define( 'POLYLANG_FILE', __FILE__ ); // this file define( 'POLYLANG_FILE', __FILE__ ); // this file
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment