Commit fe7259dc authored by Simon's avatar Simon

release 1.15.1

parent 00bf66dc
......@@ -20,9 +20,9 @@
## Production
- 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`
- 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
- update biuro/web image version in .env file (staging or www)
......
......@@ -5,7 +5,7 @@
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 ); } }
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; }
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; }
......
......@@ -4,7 +4,7 @@ Plugin Name: Loco Translate
Plugin URI: https://wordpress.org/plugins/loco-translate/
Description: Translate themes and plugins directly in WordPress
Author: Tim Whitlock
Version: 2.3.2
Version: 2.3.3
Author URI: https://localise.biz/wordpress/plugin
Text Domain: loco-translate
Domain Path: /languages/
......@@ -36,7 +36,7 @@ function loco_plugin_file(){
* @return string
*/
function loco_plugin_version(){
return '2.3.2';
return '2.3.3';
}
......
......@@ -4,7 +4,7 @@ Tags: translation, translators, localization, localisation, l10n, i18n, Gettext,
Requires at least: 4.1
Requires PHP: 5.2.4
Tested up to: 5.4
Stable tag: 2.3.2
Stable tag: 2.3.3
License: GPLv2 or later
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
== Changelog ==
= 2.3.3 =
* Fixed fatal error when class not found
= 2.3.2 =
* Removed login/email from default Last-Translator credit
* 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
== Upgrade Notice ==
= 2.3.2 =
= 2.3.3 =
* Various bug fixes and improvements
......
......@@ -48,18 +48,27 @@ class PLL_Admin_Base extends PLL_Base {
public function 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() ) {
return;
}
$this->notices = new PLL_Admin_Notices( $this );
$this->links = new PLL_Admin_Links( $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 ?
// Filter admin language for users
// 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' ) );
// Adds the languages in admin bar
......@@ -78,6 +87,8 @@ class PLL_Admin_Base extends PLL_Base {
* @since 0.1
*/
public function add_menus() {
global $admin_page_hooks;
// Prepare the list of tabs
$tabs = array( 'lang' => __( 'Languages', 'polylang' ) );
......@@ -97,11 +108,14 @@ class PLL_Admin_Base extends PLL_Base {
*/
$tabs = apply_filters( 'pll_settings_tabs', $tabs );
$parent = '';
foreach ( $tabs as $tab => $title ) {
$page = 'lang' === $tab ? 'mlang' : "mlang_$tab";
if ( empty( $parent ) ) {
$parent = $page;
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' ) );
......@@ -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 {
*/
public function post_language() {
global $post_ID;
$post_id = $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 :
( 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 {
}
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'] ) );
$post_type = sanitize_key( $_POST['post_type'] );
if ( ! post_type_exists( $post_type ) ) {
......@@ -159,8 +158,9 @@ class PLL_Admin_Classic_Editor {
ob_end_clean();
// Categories
if ( isset( $_POST['taxonomies'] ) ) {
// Not set for pages
if ( isset( $_POST['taxonomies'] ) ) { // Not set for pages
$supplemental = array();
foreach ( array_map( 'sanitize_key', $_POST['taxonomies'] ) as $taxname ) {
$taxonomy = get_taxonomy( $taxname );
......
......@@ -21,25 +21,28 @@ class PLL_Admin_Filters_Columns {
$this->model = &$polylang->model;
$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 ) {
// 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_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( '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 ) {
add_filter( 'manage_edit-' . $tax . '_columns', array( $this, 'add_term_column' ) );
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_term_rows', array( $this, 'ajax_update_term_rows' ) );
}
......@@ -60,11 +63,8 @@ class PLL_Admin_Filters_Columns {
}
foreach ( $this->model->get_languages_list() as $language ) {
// Don't add the column for the filtered language
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;
}
......@@ -77,15 +77,30 @@ class PLL_Admin_Filters_Columns {
* @return string first language column name
*/
protected function get_first_language_column() {
$columns = array();
foreach ( $this->model->get_languages_list() as $language ) {
if ( empty( $this->filter_lang ) || $language->slug != $this->filter_lang->slug ) {
$columns[] = 'language_' . $language->slug;
}
}
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
*
......@@ -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 ) );
}
$post_type_object = get_post_type_object( get_post_type( $post_id ) );
// Link to edit post ( or a translation )
if ( $id = $this->model->post->get( $post_id, $language ) ) {
// get_edit_post_link returns nothing if the user cannot edit the post
......@@ -273,7 +286,7 @@ class PLL_Admin_Filters_Columns {
esc_html( $s )
);
} elseif ( $id === $term_id ) {
$out .= printf(
$out .= sprintf(
'<span class="pll_icon_tick"><span class="screen-reader-text">%s</span></span>',
/* translators: accessibility text, %s is a native language name */
esc_html( sprintf( __( 'This item is in %s', 'polylang' ), $language->name ) )
......
......@@ -34,6 +34,8 @@ abstract class PLL_Admin_Filters_Post_Base {
// Security check as 'wp_insert_post' can be called from outside WP admin
check_admin_referer( 'pll_language', '_pll_nonce' );
$translations = array();
// Save translations after checking the translated post is in the right language
foreach ( $arr as $lang => $tr_id ) {
$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 {
// Hierarchical taxonomies
if ( 'edit' == $screen->base && $taxonomies = get_object_taxonomies( $screen->post_type, 'object' ) ) {
// Get translated hierarchical taxonomies
$hierarchical_taxonomies = array();
foreach ( $taxonomies as $taxonomy ) {
if ( $taxonomy->hierarchical && $taxonomy->show_in_quick_edit && $this->model->is_translated_taxonomy( $taxonomy->name ) ) {
$hierarchical_taxonomies[] = $taxonomy->name;
......@@ -55,6 +56,7 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
if ( ! empty( $hierarchical_taxonomies ) ) {
$terms = get_terms( $hierarchical_taxonomies, array( 'get' => 'all' ) );
$term_languages = array();
foreach ( $terms as $term ) {
if ( $lang = $this->model->term->get_language( $term->term_id ) ) {
......@@ -72,6 +74,7 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
// Hierarchical post types
if ( 'edit' == $screen->base && is_post_type_hierarchical( $screen->post_type ) ) {
$pages = get_pages();
$page_languages = array();
foreach ( $pages as $page ) {
if ( $lang = $this->model->post->get_language( $page->ID ) ) {
......
......@@ -134,7 +134,7 @@ class PLL_Admin_Filters_Term {
}
$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 = empty( $lang ) ? $this->pref_lang : $lang;
......@@ -271,6 +271,8 @@ class PLL_Admin_Filters_Term {
// If we have several terms with the same name, they are translations of each other
if ( count( $terms ) > 1 ) {
$translations = array();
foreach ( $terms as $term ) {
$translations[ $this->model->term->get_language( $term->term_id )->slug ] = $term->term_id;
}
......@@ -368,7 +370,7 @@ class PLL_Admin_Filters_Term {
$this->save_language( $term_id, $taxonomy );
if ( isset( $_POST['term_tr_lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$translations = $this->save_translations( $term_id );
$this->save_translations( $term_id );
}
}
}
......@@ -434,8 +436,8 @@ class PLL_Admin_Filters_Term {
}
$lang = $this->model->get_language( sanitize_key( $_POST['lang'] ) );
$term_id = isset( $_POST['term_id'] ) ? (int) $_POST['term_id'] : null;
$taxonomy = sanitize_key( $_POST['taxonomy'] );
$term_id = isset( $_POST['term_id'] ) ? (int) $_POST['term_id'] : null; // phpcs:ignore WordPressVIPMinimum.Variables.VariableAnalysis.UnusedVariable
$taxonomy = sanitize_key( $_POST['taxonomy'] ); // phpcs:ignore WordPressVIPMinimum.Variables.VariableAnalysis.UnusedVariable
$post_type = sanitize_key( $_POST['post_type'] );
if ( ! post_type_exists( $post_type ) || ! taxonomy_exists( $taxonomy ) ) {
......@@ -511,32 +513,40 @@ class PLL_Admin_Filters_Term {
$term_language = $this->model->get_language( sanitize_key( $_GET['term_language'] ) );
$translation_language = $this->model->get_language( sanitize_key( $_GET['translation_language'] ) );
$terms = 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 ) {
$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 ) ) {
$return[] = array(
'id' => $term->term_id,
'value' => $term->name,
'link' => $this->links->edit_term_translation_link( $term->term_id, $taxonomy, $post_type ),
);
$terms[] = $term;
}
}
// 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 ) ) {
$term = get_term( $term_id, $taxonomy );
array_unshift(
$return,
// Format the ajax response.
foreach ( $terms as $term ) {
$return[] = array(
'id' => $term->term_id,
'value' => rtrim( // Trim the seperator added at the end by WP.
get_term_parents_list(
$term->term_id,
$term->taxonomy,
array(
'id' => $term_id,
'value' => $term->name,
'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 {
$avoid_recursion = true;
$lang = $this->model->term->get_language( $term_id );
$translations = array();
foreach ( $this->model->term->get_translations( $term_id ) as $key => $tr_id ) {
if ( $lang->slug == $key ) {
......
......@@ -42,6 +42,9 @@ class PLL_Admin_Filters extends PLL_Filters {
}
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 {
}
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 {
// Delete menus locations
if ( ! empty( $this->options['nav_menus'] ) ) {
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 ] );
}
}
......@@ -211,7 +211,7 @@ class PLL_Admin_Model extends PLL_Model {
// Update menus locations
if ( ! empty( $this->options['nav_menus'] ) ) {
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 ] ) ) {
$this->options['nav_menus'][ $theme ][ $location ][ $slug ] = $this->options['nav_menus'][ $theme ][ $location ][ $old_slug ];
unset( $this->options['nav_menus'][ $theme ][ $location ][ $old_slug ] );
......@@ -321,6 +321,7 @@ class PLL_Admin_Model extends PLL_Model {
$ids = array_map( 'intval', $ids );
$lang = $this->get_language( $lang );
$tt_id = 'term' === $type ? $lang->tl_term_taxonomy_id : $lang->term_taxonomy_id;
$values = array();
foreach ( $ids as $id ) {
$values[] = $wpdb->prepare( '( %d, %d )', $id, $tt_id );
......@@ -334,6 +335,7 @@ class PLL_Admin_Model extends PLL_Model {
if ( 'term' === $type ) {
clean_term_cache( $ids, 'term_language' );
$translations = array();
foreach ( $ids as $id ) {
$translations[] = array( $lang->slug => $id );
......@@ -359,6 +361,10 @@ class PLL_Admin_Model extends PLL_Model {
global $wpdb;
$taxonomy = $type . '_translations';
$terms = array();
$slugs = array();
$description = array();
$count = array();
foreach ( $translations as $t ) {
$term = uniqid( 'pll_' ); // the term name
......@@ -377,6 +383,8 @@ class PLL_Admin_Model extends PLL_Model {
// Get all terms with their term_id
// PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
$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
foreach ( $terms as $term ) {
......@@ -392,6 +400,7 @@ class PLL_Admin_Model extends PLL_Model {
// Get all terms with term_taxonomy_id
$terms = get_terms( $taxonomy, array( 'hide_empty' => false ) );
$trs = array();
// Prepare objects relationships
foreach ( $terms as $term ) {
......@@ -493,6 +502,10 @@ class PLL_Admin_Model extends PLL_Model {
global $wpdb;
$terms = get_terms( array( 'post_translations', 'term_translations' ) );
$term_ids = array();
$dr = array();
$dt = array();
$ut = array();
foreach ( $terms as $term ) {
$term_ids[ $term->taxonomy ][] = $term->term_id;
......@@ -563,6 +576,8 @@ class PLL_Admin_Model extends PLL_Model {
// The nav menus stored in theme locations should be in the default language
$theme = get_stylesheet();
if ( ! empty( $this->options['nav_menus'][ $theme ] ) ) {
$menus = array();
foreach ( $this->options['nav_menus'][ $theme ] as $key => $loc ) {
$menus[ $key ] = empty( $loc[ $slug ] ) ? 0 : $loc[ $slug ];
}
......
......@@ -94,8 +94,11 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
$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 );
$data['strings'] = PLL_Switcher::get_switcher_options( 'menu', 'string' ); // The strings for the options
$data['title'] = __( 'Languages', 'polylang' ); // The title
$data = array(
'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
$items = get_posts(
......@@ -109,7 +112,6 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
);
// The options values for the language switcher
$data['val'] = array();
foreach ( $items as $item ) {
$data['val'][ $item ] = get_post_meta( $item, '_pll_menu_item', true );
}
......@@ -143,7 +145,7 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
}
}
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;
}
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 {
* @return array
*/
public function update_nav_menu_locations( $locations ) {
$default = $this->options['default_lang'];
// Extract language and menu from locations
foreach ( $locations as $loc => $menu ) {
$infos = $this->explode_location( $loc );
......@@ -232,7 +232,7 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
}
if ( is_array( $menus ) ) {
foreach ( $menus as $loc => $menu ) {
foreach ( array_keys( $menus ) as $loc ) {
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' ) ) {
$menus[ $this->combine_location( $loc, $lang ) ] = $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ];
......
......@@ -6,6 +6,7 @@
* and only on dashboard, plugins and Polylang admin pages
*
* @since 2.3.9
* @since 2.7 Dismissed notices are stored in an option instead of a user meta
*/
class PLL_Admin_Notices {
private static $notices = array();
......@@ -57,8 +58,22 @@ class PLL_Admin_Notices {
* @return bool
*/
public static function is_dismissed( $notice ) {
$dismissed = get_user_meta( get_current_user_id(), 'pll_dismissed_notices', true );
return is_array( $dismissed ) && in_array( $notice, $dismissed );
$dismissed = get_option( 'pll_dismissed_notices', array() );
// 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,13 +81,24 @@ class PLL_Admin_Notices {
*
* @since 2.3.9
*
* @param string $notice The notice name.
* @return bool
*/
protected function can_display_notice() {
protected function can_display_notice( $notice ) {
$screen = get_current_screen();
$screen_id = sanitize_title( __( 'Languages', 'polylang' ) );
return in_array(
/**
* Filter admin notices which can be displayed
*
* @since 2.7.0
*
* @param bool $display Whether the notice should be displayed or not.
* @param string $notice The notice name.
*/
return apply_filters(
'pll_can_display_notice',
in_array(
$screen->id,
array(
'dashboard',
......@@ -81,6 +107,8 @@ class PLL_Admin_Notices {
$screen_id . '_page_mlang_strings',
$screen_id . '_page_mlang_settings',
)
),
$notice
);
}
......@@ -92,13 +120,11 @@ class PLL_Admin_Notices {
* @param string $notice
*/
public static function dismiss( $notice ) {
if ( ! $dismissed = get_user_meta( get_current_user_id(), 'pll_dismissed_notices', true ) ) {
$dismissed = array();
}
$dismissed = get_option( 'pll_dismissed_notices', array() );
if ( ! in_array( $notice, $dismissed ) ) {
$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 {
* @since 2.3.9
*/
public function display_notices() {
if ( current_user_can( 'manage_options' ) && $this->can_display_notice() ) {
if ( current_user_can( 'manage_options' ) ) {
// Core notices
if ( defined( 'WOOCOMMERCE_VERSION' ) && ! defined( 'PLLWC_VERSION' ) && $this->can_display_notice( 'pllwc' ) && ! $this->is_dismissed( 'pllwc' ) ) {
$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
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">
<?php
......@@ -166,7 +197,6 @@ class PLL_Admin_Notices {
* @since 2.3.9
*/
private function pllwc_notice() {
if ( defined( 'WOOCOMMERCE_VERSION' ) && ! defined( 'PLLWC_VERSION' ) && ! $this->is_dismissed( 'pllwc' ) ) {
?>
<div class="pll-notice notice notice-warning">
<?php $this->dismiss_button( 'pllwc' ); ?>
......@@ -183,7 +213,6 @@ class PLL_Admin_Notices {
</div>
<?php
}
}
/**
* Displays a notice asking for a review
......@@ -191,7 +220,6 @@ class PLL_Admin_Notices {
* @since 2.3.9
*/
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">
<?php $this->dismiss_button( 'review' ); ?>
......@@ -208,5 +236,4 @@ class PLL_Admin_Notices {
</div>
<?php
}
}
}
......@@ -86,8 +86,8 @@ class PLL_Admin_Static_Pages extends PLL_Static_Pages {
*
* @since 1.8
*
* @param array $post_states
* @param object $post
* @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 ) {
......
......@@ -118,7 +118,6 @@ class PLL_Admin_Strings {
* @return string
*/
public static function sanitize_string_translation( $translation, $name ) {
$translation = wp_unslash( trim( $translation ) );
if ( false !== ( $option = array_search( $name, self::$default_strings['options'], true ) ) ) {
$translation = sanitize_option( $option, $translation );
......
......@@ -25,8 +25,12 @@
* block_editor => reference to PLL_Admin_Block_Editor object
* classic_editor => reference to PLL_Admin_Classic_Editor 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 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 {
public $filters, $filters_columns, $filters_post, $filters_term, $nav_menu, $sync, $filters_media;
......@@ -61,11 +65,6 @@ class PLL_Admin extends PLL_Admin_Base {
if ( $this->model->get_languages_list() ) {
add_action( 'wp_loaded', array( $this, 'add_filters' ), 5 );
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 {
* Setup filters for admin pages
*
* @since 1.2
* @since 2.7 instantiate a PLL_Bulk_Translate instance.
*/
public function add_filters() {
// All these are separated just for convenience and maintainability
......@@ -127,6 +127,13 @@ class PLL_Admin extends PLL_Admin_Base {
$this->posts = new PLL_CRUD_Posts( $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
if ( $this->options['media_support'] && class_exists( 'PLL_Admin_Advanced_Media' ) ) {
$this->advanced_media = new PLL_Admin_Advanced_Media( $this );
......@@ -146,6 +153,10 @@ class PLL_Admin extends PLL_Admin_Base {
$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
if ( pll_use_block_editor_plugin() ) {
$this->block_editor_plugin = new PLL_Block_Editor_Plugin( $this );
......
......@@ -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-edit-column">
<?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
printf(
'<input type="hidden" name="media_tr_lang[%s]" value="%d" />',
......@@ -31,7 +31,7 @@ if ( ! defined( 'ABSPATH' ) ) {
echo $this->links->edit_post_translation_link( $translation_id ); // phpcs:ignore WordPress.Security.EscapeOutput
} else {
// 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>
......
......@@ -21,6 +21,14 @@
font-family: 'dashicons';
content: "\f155";
}
.pll-icon:before{
display: inline-block;
text-align: left;
width: 15px;
}
.pll-circle:before{
content: "\25cf";
}
.form-field input[type="radio"] {
width: auto;
......@@ -324,6 +332,10 @@ td[class*='column-language_'] {
text-decoration: none;
}
.pll-notice .button {
margin-right: 10px;
}
/* Bulk translate */
.bulk-translate-save .button {
margin-right: 20px;
......
......@@ -24,11 +24,17 @@
position: relative;
margin: 0;
padding: 3px 1em 3px .4em;
cursor: pointer;
min-height: 0; /* support: IE7 */
/* support: IE10, see #8844 */
list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
}
.rtl .ui-menu .ui-menu-item {
text-align: right;
}
/* icon support */
.ui-menu-icons {
position: relative;
......@@ -37,6 +43,10 @@
.ui-menu-icons .ui-menu-item {
padding-left: 2em;
}
.rtl .ui-menu-icons .ui-menu-item {
padding-left: 1em;
padding-right: 2em;
}
/* left-aligned */
.ui-selectmenu-text .ui-icon,
......@@ -44,10 +54,16 @@
position: absolute;
top: 0;
bottom: 0;
left: .2em;
left: .3em;
margin: auto 0;
}
.rtl .ui-selectmenu-text .ui-icon,
.rtl .ui-menu .ui-icon {
right: .3em;
left: auto;
}
/* right-aligned */
.ui-menu .ui-menu-icon {
left: auto;
......@@ -97,8 +113,15 @@
margin-top: -10px;
position: absolute;
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 {
text-align: left;
padding: 0.2em 2.1em 0.2em 2em;
......@@ -109,6 +132,11 @@
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-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 {
}
/**
* 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
*
* @return object browser preferred language or default 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 ] ) ) {
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 {
* Polylang fallbacks to the default language
*
* @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'] );
}
......@@ -274,6 +285,7 @@ abstract class PLL_Choose_Lang {
*/
if ( $redirect = apply_filters( 'pll_redirect_home', $redirect ) ) {
$this->maybe_setcookie();
header( 'Vary: Accept-Language' );
wp_safe_redirect( $redirect, 302, POLYLANG );
exit;
}
......
......@@ -185,12 +185,12 @@ class PLL_Frontend_Auto_Translate {
// Array of post ids
// 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();
if ( ! empty( $qv[ $key ] ) ) {
// 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
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' ) ) ) {
return;
}
......@@ -216,6 +216,8 @@ class PLL_Frontend_Auto_Translate {
*/
public function get_terms_args( $args, $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 ) {
$arr[] = ( $tr = $this->get_term( $id ) ) ? $tr : $id;
}
......
......@@ -175,6 +175,8 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
return;
}
$urls = array();
// Google recommends to include self link https://support.google.com/webmasters/answer/189077?hl=en
foreach ( $this->model->get_languages_list() as $language ) {
if ( $url = $this->links->get_translation_url( $language ) ) {
......@@ -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 )
if ( ! empty( $urls ) && count( $urls ) > 1 ) {
$languages = array();
$hreflangs = array();
// Prepare the list of languages to remove the country code
foreach ( array_keys( $urls ) as $locale ) {
......@@ -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+)
foreach ( $traces as $trace ) {
......
......@@ -55,7 +55,6 @@ class PLL_Frontend_Links extends PLL_Links {
*/
if ( ! $url = apply_filters( 'pll_pre_translation_url', '', $language, $queried_object_id ) ) {
$qv = $wp_query->query_vars;
$hide = $this->options['default_lang'] == $language->slug && $this->options['hide_default'];
// 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 ) ) {
......@@ -96,7 +95,7 @@ class PLL_Frontend_Links extends PLL_Links {
$lang = $this->model->term->get_language( $term->term_id );
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 ) ) {
......@@ -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
*/
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 {
$new_items = array();
$offset = 0;
foreach ( $items as $key => $item ) {
foreach ( $items as $item ) {
if ( $options = get_post_meta( $item->ID, '_pll_menu_item', true ) ) {
$i = 0;
......@@ -219,7 +219,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
// First get multilingual menu locations from DB
$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 ];
}
......@@ -275,7 +275,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
if ( ! $menu && ! $args['theme_location'] ) {
$menus = wp_get_nav_menus();
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 ) {
if ( in_array( $menu_maybe->term_id, $menus ) && ! empty( $menus[ $this->curlang->slug ] ) ) {
$args['menu'] = $menus[ $this->curlang->slug ];
......
......@@ -92,12 +92,14 @@ class PLL_Frontend extends PLL_Base {
// Share term slugs
if ( $this->options['force_lang'] && class_exists( 'PLL_Share_Term_Slug' ) ) {
$this->share_term_slug = version_compare( $GLOBALS['wp_version'], '4.8', '<' ) ?
new PLL_Frontend_Share_Term_Slug( $this ) :
new PLL_Share_Term_Slug( $this );
$this->share_term_slug = 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' ) ) {
$this->sync_post = new PLL_Sync_Post( $this );
}
......
......@@ -372,9 +372,9 @@ function pll_get_term_translations( $term_id ) {
*
* @since 1.5
*
* @param string $lang language code
* @param array $args ( accepted keys: post_type, m, year, monthnum, day, author, author_name, post_format )
* @return int posts count
* @param string $lang Language code.
* @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.
*/
function pll_count_posts( $lang, $args = array() ) {
return PLL()->model->count_posts( PLL()->model->get_language( $lang ), $args );
......
......@@ -139,7 +139,7 @@ abstract class PLL_Base {
foreach ( $this as $prop => &$obj ) {
if ( is_object( $obj ) && method_exists( $obj, $func ) ) {
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
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions
sprintf(
......@@ -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
sprintf(
'Call to undefined function PLL()->%1$s() in %2$s on line %3$s' . "\nError handler",
......
......@@ -30,6 +30,9 @@ class Polylang {
require_once PLL_INC . '/functions.php'; // VIP functions
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 );
// Stopping here if we are going to deactivate the plugin ( avoids breaking rewrite rules )
......@@ -98,7 +101,7 @@ class Polylang {
foreach ( $dirs as $dir ) {
if ( file_exists( $file = "$dir/$class.php" ) ) {
require_once $file;
require_once $file; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable
return;
}
}
......@@ -155,6 +158,17 @@ class Polylang {
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
* May be overridden by a plugin if set before plugins_loaded, 1
......@@ -177,9 +191,9 @@ class Polylang {
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' ) ) {
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 {
*
* @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 );
$links_model = $model->get_links_model();
......
......@@ -227,7 +227,7 @@ class PLL_CRUD_Posts {
if ( ! empty( $ids ) ) {
// 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.
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.
}
......@@ -239,9 +239,9 @@ class PLL_CRUD_Posts {
*
* @since 1.8
*
* @param int $post_id
* @param string|object $lang
* @return int id of the translated media
* @param int $post_id Original attachment id.
* @param string|object $lang New translation language.
* @return int Attachment id of the translated media.
*/
public function create_media_translation( $post_id, $lang ) {
if ( empty( $post_id ) ) {
......@@ -254,30 +254,34 @@ class PLL_CRUD_Posts {
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 )
add_filter( 'pll_enable_duplicate_media', '__return_false', 99 ); // Avoid a conflict with automatic duplicate at upload
// 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.
$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->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 ) );
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.
if ( $data = wp_get_attachment_metadata( $post_id, true ) ) { // Unfiltered.
wp_update_attachment_metadata( $tr_id, wp_slash( $data ) ); // Directly uses update_post_meta, so expects slashed.
}
// Copy metadata, attached file and alternative text
foreach ( array( '_wp_attachment_metadata', '_wp_attached_file', '_wp_attachment_image_alt' ) as $key ) {
if ( $meta = get_post_meta( $post_id, $key, true ) ) {
add_post_meta( $tr_id, $key, wp_slash( $meta ) );
// 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.
}
// Copy alternative text. Direct use of the meta as there is no filtered wrapper to manipulate it.
if ( $text = get_post_meta( $post_id, '_wp_attachment_image_alt', true ) ) {
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 );
if ( ! $translations && $src_lang = $this->model->post->get_language( $post_id ) ) {
$translations[ $src_lang->slug ] = $post_id;
}
$translations[ $lang->slug ] = $tr_id;
$this->model->post->save_translations( $tr_id, $translations );
......@@ -286,9 +290,9 @@ class PLL_CRUD_Posts {
*
* @since 1.6.4
*
* @param int $post_id post id of the source media
* @param int $tr_id post id of the new media translation
* @param string $slug language code of the new translation
* @param int $post_id Post id of the source media.
* @param int $tr_id Post id of the new media translation.
* @param string $slug Language code of the new translation.
*/
do_action( 'pll_translate_media', $post_id, $tr_id, $lang->slug );
return $tr_id;
......
......@@ -336,8 +336,8 @@ class PLL_Filters {
*/
public function user_data_exporter( $email_address ) {
$email_address = trim( $email_address );
$data_to_export = array();
$user_data_to_export = array();
if ( $user = get_user_by( 'email', $email_address ) ) {
foreach ( $this->model->get_languages_list() as $lang ) {
......
......@@ -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.
*/
function wpcom_vip_get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) {
return get_page_by_title( $page_title, $output, $post_type );
}
}
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 );
return get_page_by_title( $page_title, $output, $post_type ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.get_page_by_title_get_page_by_title
}
}
......
......@@ -102,7 +102,7 @@ class PLL_Language {
* @return array Flag informations.
*/
public static function get_flag_informations( $code ) {
$flag['url'] = '';
$flag = array( 'url' => '' );
// Polylang builtin flags
if ( ! empty( $code ) && file_exists( POLYLANG_DIR . ( $file = '/flags/' . $code . '.png' ) ) ) {
......@@ -145,7 +145,7 @@ class PLL_Language {
* @since 1.2
*/
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 ?
$directories = array(
......@@ -210,18 +210,31 @@ class PLL_Language {
*/
$this->{$key} = apply_filters(
'pll_get_flag',
empty( $flag['src'] ) ? '' : sprintf(
'<img src="%s" title="%s" alt="%s"%s%s />',
self::get_flag_html( $flag, $title, $this->name ),
$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'],
esc_attr( $title ),
esc_attr( $this->name ),
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'] )
),
$this->slug
);
}
}
/**
* Replace flag by custom flag
......
......@@ -153,7 +153,7 @@ class PLL_License {
$response = wp_remote_post(
$this->api_url,
array(
'timeout' => 15,
'timeout' => 3,
'sslverify' => false,
'body' => $api_params,
)
......@@ -175,4 +175,122 @@ class PLL_License {
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 {
if ( ! empty( $lang ) ) {
$base = $this->options['rewrite'] ? '' : 'language/';
$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 ) ) {
$pattern = str_replace( '/', '\/', $root );
$pattern = preg_quote( $root, '#' );
$pattern = '#' . $pattern . '#';
return preg_replace( $pattern, $new, $url, 1 ); // Only once
}
......@@ -80,6 +80,8 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
* @return string modified url
*/
public function remove_language_from_link( $url ) {
$languages = array();
foreach ( $this->model->get_languages_list() as $language ) {
if ( ! $this->options['hide_default'] || $this->options['default_lang'] != $language->slug ) {
$languages[] = $language->slug;
......@@ -87,10 +89,10 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
}
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 = '#' . $pattern . ( $this->options['rewrite'] ? '' : 'language\/' ) . '(' . implode( '|', $languages ) . ')(\/|$)#';
$pattern = preg_quote( $root, '#' );
$pattern = '#' . $pattern . ( $this->options['rewrite'] ? '' : 'language/' ) . '(' . implode( '|', $languages ) . ')(/|$)#';
$url = preg_replace( $pattern, $root, $url );
}
return $url;
......@@ -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;
$pattern = wp_parse_url( $root . ( $this->options['rewrite'] ? '' : 'language/' ), PHP_URL_PATH );
$pattern = str_replace( '/', '\/', $pattern );
$pattern = '#^' . $pattern . '(' . implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')(\/|$)#';
$pattern = preg_quote( $pattern, '#' );
$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
}
......
......@@ -38,7 +38,7 @@ class PLL_Links_Domain extends PLL_Links_Abstract_Domain {
*/
public function add_language_to_link( $url, $lang ) {
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;
}
......@@ -54,7 +54,7 @@ class PLL_Links_Domain extends PLL_Links_Abstract_Domain {
*/
public function remove_language_from_link( $url ) {
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;
}
......
......@@ -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 $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 {
* @return string modified url
*/
public function remove_language_from_link( $url ) {
$languages = array();
foreach ( $this->model->get_languages_list() as $language ) {
if ( ! $this->options['hide_default'] || $this->options['default_lang'] != $language->slug ) {
$languages[] = $language->slug;
......@@ -56,7 +58,7 @@ class PLL_Links_Subdomain extends PLL_Links_Abstract_Domain {
}
if ( ! empty( $languages ) ) {
$url = preg_replace( '#:\/\/(' . implode( '|', $languages ) . ')\.#', $this->www, $url );
$url = preg_replace( '#://(' . implode( '|', $languages ) . ')\.#', $this->www, $url );
}
return $url;
......
......@@ -182,6 +182,7 @@ class PLL_Model {
$this->cache->set( 'language:' . $lang->tl_term_id, $lang );
$this->cache->set( 'language:' . $lang->slug, $lang );
$this->cache->set( 'language:' . $lang->locale, $lang );
$this->cache->set( 'language:' . $lang->w3c, $lang );
}
$return = $this->cache->get( 'language:' . $value );
}
......@@ -427,6 +428,7 @@ class PLL_Model {
global $wpdb;
$term_name = trim( wp_unslash( $term_name ) );
$term_name = _wp_specialchars( $term_name );
$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";
......@@ -448,13 +450,13 @@ class PLL_Model {
* @since 1.2
*
* @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
*/
public function count_posts( $lang, $q = array() ) {
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'] ) ) {
$q['post_type'] = array( $q['post_type'] );
......@@ -476,7 +478,7 @@ class PLL_Model {
if ( false === $counts ) {
$select = "SELECT pll_tr.term_taxonomy_id, COUNT( * ) AS num_posts FROM {$wpdb->posts}";
$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 .= $this->post->where_clause( $this->get_languages_list() );
$groupby = ' GROUP BY pll_tr.term_taxonomy_id';
......@@ -610,7 +612,7 @@ class PLL_Model {
if ( ! empty( $o ) && is_object( $this->$o ) && method_exists( $this->$o, $f ) ) {
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
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions
......@@ -627,7 +629,7 @@ class PLL_Model {
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
sprintf(
'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 {
static $once;
global $_wp_registered_nav_menus;
$arr = array();
if ( isset( $_wp_registered_nav_menus ) && ! $once ) {
foreach ( $_wp_registered_nav_menus as $loc => $name ) {
foreach ( $this->model->get_languages_list() as $lang ) {
......
......@@ -51,9 +51,7 @@ class PLL_REST_Request extends PLL_Base {
// Share term slugs
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', '<' ) ?
new PLL_Frontend_Share_Term_Slug( $this ) :
new PLL_Share_Term_Slug( $this );
$this->share_term_slug = new PLL_Share_Term_Slug( $this );
}
// Translate slugs, only for pretty permalinks
......@@ -63,6 +61,10 @@ class PLL_REST_Request extends PLL_Base {
$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' ) ) {
$this->sync_post = new PLL_Sync_Post_REST( $this );
}
......
......@@ -42,8 +42,8 @@ class PLL_Switcher {
* @return array
*/
protected function get_elements( $links, $args ) {
$first = true;
$out = array();
foreach ( $links->model->get_languages_list( array( 'hide_empty' => $args['hide_if_empty'] ) ) as $language ) {
$id = (int) $language->term_id;
......@@ -100,7 +100,7 @@ class PLL_Switcher {
$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 {
// Javascript to switch the language when using a dropdown list
if ( $args['dropdown'] ) {
$urls = array();
foreach ( $links->model->get_languages_list() as $language ) {
$url = $links->get_translation_url( $language );
$urls[ $language->slug ] = $args['force_home'] || empty( $url ) ? $links->get_home_url( $language ) : $url;
......
......@@ -50,6 +50,7 @@ abstract class PLL_Translated_Object {
$taxonomies = array( $this->tax_language, $this->tax_translations );
// query terms
$terms = array();
foreach ( wp_get_object_terms( $object_id, $taxonomies, array( 'update_term_meta_cache' => false ) ) as $t ) {
$terms[ $t->taxonomy ] = $t;
if ( $t->taxonomy == $taxonomy ) {
......@@ -239,7 +240,6 @@ abstract class PLL_Translated_Object {
* @return string where clause
*/
public function where_clause( $lang ) {
global $wpdb;
$tt_id = $this->tax_tt;
// $lang is an object
......@@ -251,6 +251,7 @@ abstract class PLL_Translated_Object {
// $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
$slugs = is_array( $lang ) ? $lang : explode( ',', $lang );
$languages = array();
foreach ( $slugs as $slug ) {
$languages[] = absint( $this->model->get_language( $slug )->$tt_id );
}
......
......@@ -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
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
......@@ -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 ) ) ) {
// 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_set_object_terms( $id, $group, 'term_translations' );
}
......@@ -158,6 +158,8 @@ class PLL_Translated_Term extends PLL_Translated_Object {
* @return array unmodified $terms
*/
public function _prime_terms_cache( $terms, $taxonomies ) {
$term_ids = array();
if ( is_array( $terms ) && $this->model->is_translated_taxonomy( $taxonomies ) ) {
foreach ( $terms as $term ) {
$term_ids[] = is_object( $term ) ? $term->term_id : (int) $term;
......
......@@ -101,8 +101,8 @@ class PLL_Walker_Dropdown extends Walker {
$output .= sprintf(
'<select name="%1$s"%2$s%3$s%4$s>' . "\n" . '%5$s' . "\n" . '</select>' . "\n",
$name = esc_attr( $args['name'] ),
isset( $args['id'] ) && ! $args['id'] ? '' : ' id="' . ( empty( $args['id'] ) ? $name : esc_attr( $args['id'] ) ) . '"',
esc_attr( $args['name'] ),
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'] ) . '"',
disabled( empty( $args['disabled'] ), false, false ),
parent::walk( $elements, $max_depth, $args )
......
......@@ -64,7 +64,7 @@ class PLL_Widget_Languages extends WP_Widget {
* @return array Settings to save or bool false to cancel saving
*/
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 ) {
$instance[ $key ] = ! empty( $new_instance[ $key ] ) ? 1 : 0;
}
......
......@@ -40,7 +40,7 @@ class PLL_Install extends PLL_Install_Base {
'<div class="error"><p>%s</p></div>',
sprintf(
/* 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 ),
PHP_VERSION,
esc_html( PLL_MIN_PHP_VERSION )
......@@ -62,7 +62,7 @@ class PLL_Install extends PLL_Install_Base {
'<div class="error"><p>%s</p></div>',
sprintf(
/* 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( $wp_version ),
esc_html( PLL_MIN_WP_VERSION )
......
......@@ -89,7 +89,7 @@ class PLL_Upgrade {
* @since 1.2
*/
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, '<' ) ) {
call_user_func( array( $this, 'upgrade_' . str_replace( '.', '_', $version ) ) );
}
......@@ -143,7 +143,7 @@ class PLL_Upgrade {
// Update strings register with icl_register_string
$strings = get_option( 'polylang_wpml_strings' );
if ( $strings ) {
foreach ( $strings as $key => $string ) {
foreach ( array_keys( $strings ) as $key ) {
$strings[ $key ]['icl'] = 1;
}
update_option( 'polylang_wpml_strings', $strings );
......@@ -180,6 +180,7 @@ class PLL_Upgrade {
global $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
$lang_tt_ids = array();
foreach ( $languages as $lang ) {
// First update language with new storage for locale and text direction
......@@ -209,7 +210,11 @@ class PLL_Upgrade {
// Translations
foreach ( array( 'post', 'term' ) as $type ) {
$table = $type . 'meta';
$terms = $slugs = $tts = $trs = array();
$terms = array();
$slugs = array();
$tts = array();
$trs = array();
$description = array();
// Get all translated objects
// PHPCS:ignore WordPress.DB.PreparedSQL
......@@ -307,6 +312,8 @@ class PLL_Upgrade {
// Multilingal locations and switcher item were stored in a dedicated option
if ( version_compare( $this->options['version'], '1.1', '<' ) ) {
if ( $menu_lang = get_option( 'polylang_nav_menus' ) ) {
$locations = array();
foreach ( $menu_lang as $location => $arr ) {
if ( ! in_array( $location, array_keys( get_registered_nav_menus() ) ) ) {
continue;
......@@ -355,7 +362,7 @@ class PLL_Upgrade {
// Clean the WP option as it was a bad idea to pollute it
if ( version_compare( $this->options['version'], '1.2', '<' ) ) {
foreach ( $menus as $loc => $menu ) {
if ( $pos = strpos( $loc, '#' ) ) {
if ( strpos( $loc, '#' ) ) {
unset( $menus[ $loc ] );
}
}
......@@ -518,6 +525,8 @@ class PLL_Upgrade {
return;
}
$translations_to_load = array();
foreach ( $translations as $translation ) {
if ( in_array( $translation['language'], $languages ) ) {
$translation['type'] = 'core';
......@@ -608,4 +617,29 @@ class PLL_Upgrade {
protected function upgrade_2_3() {
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)});
......@@ -3,19 +3,22 @@
*
* @since 2.5
*/
wp.apiFetch.use( function( options, next ) {
wp.apiFetch.use(
function( options, next ) {
// If options.url is defined, this is not a REST request but a direct call to post.php for legacy metaboxes.
if ( 'undefined' === typeof options.url ) {
if ( 'undefined' === typeof options.data ) {
// GET
options.path += ( ( options.path.indexOf ( '?' ) >= 0 ) ? '&lang=' : '?lang=' ) + getCurrentLanguage();
options.path += ( ( options.path.indexOf( '?' ) >= 0 ) ? '&lang=' : '?lang=' ) + getCurrentLanguage();
} else {
// PUT, POST
options.data.lang = getCurrentLanguage();
}
}
return next( options );
} );
}
);
/**
* Get the language from the HTML form
......@@ -33,9 +36,11 @@ function getCurrentLanguage() {
*
* @since 2.5
*/
jQuery( document ).ready(function( $ ) {
jQuery( document ).ready(
function( $ ) {
// savePost after changing the post's language and reload page for refreshing post translated data
$( '.post_lang_choice' ).change(function() {
$( '.post_lang_choice' ).change(
function() {
const select = wp.data.select;
const dispatch = wp.data.dispatch;
const subscribe = wp.data.subscribe;
......@@ -43,10 +48,12 @@ jQuery( document ).ready(function( $ ) {
let unsubscribe = null;
// Listen if the savePost is done
const savePostIsDone = new Promise( function( resolve, reject ) {
unsubscribe = subscribe( function() {
const isSavePostSucceeded = select('core/editor').didPostSaveRequestSucceed();
const isSavePostFailed = select('core/editor').didPostSaveRequestFail();
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();
......@@ -54,20 +61,25 @@ jQuery( document ).ready(function( $ ) {
resolve();
}
}
} );
});
}
);
}
);
// Specific case for empty posts
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');
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 ) {
// Change the new_lang parameter with the new language value for reloading the page
// WPCS location.search is never written in the page, just used to relaoad page ( See line 94 ) with the right value of new_lang
// new_lang input is controlled server side in PHP. The value come from the dropdown list of language returned and escaped server side
if ( -1 != location.search.indexOf( 'new_lang' ) ) {
window.location.search = window.location.search.replace( /(?:new_lang=[^&]*)(&)?(.*)/, 'new_lang=' + this.value + '$1$2' );;
// use regexp non capturing group to replace new_lang parameter no matter where it is and capture other parameters which can be behind it
window.location.search = window.location.search.replace( /(?:new_lang=[^&]*)(&)?(.*)/, 'new_lang=' + this.value + '$1$2' ); // phpcs:ignore WordPressVIPMinimum.JS.Window.location, WordPressVIPMinimum.JS.Window.VarAssignment
} else {
window.location.search = window.location.search + ( ( -1 != window.location.search.indexOf( '?' ) ) ? '&' : '?' ) + 'new_lang=' + this.value;
window.location.search = window.location.search + ( ( -1 != window.location.search.indexOf( '?' ) ) ? '&' : '?' ) + 'new_lang=' + this.value; // phpcs:ignore WordPressVIPMinimum.JS.Window.location, WordPressVIPMinimum.JS.Window.VarAssignment
}
}
}
......@@ -75,21 +87,26 @@ jQuery( document ).ready(function( $ ) {
// For empty posts savePost does nothing
dispatch( 'core/editor' ).savePost();
savePostIsDone
.then( function() {
savePostIsDone.then(
function() {
// If the post is well saved, we can reload the page
unsubscribe();
window.location.reload();
}, function() {
},
function() {
// If the post save failed
unsubscribe();
} )
.catch( function() {
}
).catch(
function() {
// If an exception is thrown
unsubscribe();
} );
} );
} );
}
);
}
);
}
);
/**
* Handles internals of the metabox:
......@@ -97,9 +114,11 @@ jQuery( document ).ready(function( $ ) {
*
* @since 1.5
*/
jQuery( document ).ready(function( $ ) {
jQuery( document ).ready(
function( $ ) {
// Ajax for changing the post's language in the languages metabox
$( '.post_lang_choice' ).change(function() {
$( '.post_lang_choice' ).change(
function() {
var data = {
action: 'post_lang_choice',
lang: $( this ).val(),
......@@ -108,29 +127,41 @@ jQuery( document ).ready(function( $ ) {
_pll_nonce: $( '#_pll_nonce' ).val()
}
$.post( ajaxurl, data , function( response ) {
$.post(
ajaxurl,
data,
function( response ) {
var res = wpAjax.parseAjaxResponse( response, 'ajax-response' );
$.each( res.responses, function() {
$.each(
res.responses,
function() {
switch ( this.what ) {
case 'translations': // Translations fields
$( '.translations' ).html( this.data );
// Data is built and come from server side and is well escaped when necessary
$( '.translations' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
init_translations();
break;
case 'flag': // Flag in front of the select dropdown
$( '.pll-select-flag' ).html( this.data );
// Data is built and come from server side and is well escaped when necessary
$( '.pll-select-flag' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
break;
}
});
});
});
}
);
}
);
}
);
// Translations autocomplete input box
function init_translations() {
$( '.tr_lang' ).each(function(){
$( '.tr_lang' ).each(
function(){
var tr_lang = $( this ).attr( 'id' ).substring( 8 );
var td = $( this ).parent().parent().siblings( '.pll-edit-column' );
$( this ).autocomplete({
$( this ).autocomplete(
{
minLength: 0,
source: ajaxurl + '?action=pll_posts_not_translated' +
......@@ -141,24 +172,33 @@ jQuery( document ).ready(function( $ ) {
select: function( event, ui ) {
$( '#htr_lang_' + tr_lang ).val( ui.item.id );
td.html( ui.item.link );
// ui.item.link is built and come from server side and is well escaped when necessary
td.html( ui.item.link ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
},
});
}
);
// When the input box is emptied
$( this ).blur(function() {
$( this ).blur(
function() {
if ( ! $( this ).val() ) {
$( '#htr_lang_' + tr_lang ).val( 0 );
td.html( td.siblings( '.hidden' ).children().clone() );
// Value is retrieved from HTML already generated server side
td.html( td.siblings( '.hidden' ).children().clone() ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
}
}
);
}
});
});
);
}
init_translations();
// Handle the response to a click on a Languages metabox button
$( '#ml_box' ).on( 'click', '.pll-button', function(){
$( '#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();
......@@ -171,14 +211,23 @@ jQuery( document ).ready(function( $ ) {
_pll_nonce: $( '#_pll_nonce' ).val()
}
$.post( ajaxurl, data , function( response ){
$.post(
ajaxurl,
data,
function( response ){
var res = wpAjax.parseAjaxResponse( response, 'ajax-response' );
$.each( res.responses, function() {
$.each(
res.responses,
function() {
id = id.replace( '[', '\\[' ).replace( ']', '\\]' );
$( '#' + id ).toggleClass( 'wp-ui-text-highlight' ).attr( 'title', this.data ).children( 'span' ).html( this.data );
$( '#' + id ).toggleClass( 'wp-ui-text-highlight' ).attr( 'title', this.data ).children( 'span' ).text( this.data );
$( 'input[name="' + id + '"]' ).val( ! data['value'] );
});
});
}
});
});
);
}
);
}
}
);
}
);
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
// tag suggest in metabox
(function( $ ){
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
$.ajaxPrefilter(
function( options, originalOptions, jqXHR ) {
if ( 'string' === typeof options.data && -1 !== options.url.indexOf( 'action=ajax-tag-search' ) && ( lang = $( '.post_lang_choice' ).val() ) ) {
options.data = 'lang=' + lang + '&' + options.data;
}
});
}
);
})( jQuery );
// overrides tagBox.get
......@@ -20,16 +22,23 @@
tax: tax
}
$.post( ajaxurl, data, function( r, stat ) {
$.post(
ajaxurl,
data,
function( r, stat ) {
if ( 0 == r || 'success' != stat ) {
r = wpAjax.broken;
}
r = $( '<div id="tagcloud-' + tax + '" class="the-tagcloud">' + r + '</div>' );
$( 'a', r ).click(function(){
// @see code from WordPress core https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/js/tags-box.js#L291
// @see wp_generate_tag_cloud function which generate the escaped HTML https://github.com/WordPress/WordPress/blob/a02b5cc2a8eecb8e076fbb7cf4de7bd2ec8a8eb1/wp-includes/category-template.php#L966-L975
r = $( '<div />' ).addClass( 'the-tagcloud' ).attr( 'id', 'tagcloud-' + tax ).html( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
$( 'a', r ).click(
function(){
tagBox.flushTags( $( this ).closest( '.inside' ).children( '.tagsdiv' ), this );
return false;
});
}
);
// add an if else condition to allow modifying the tags outputed when switching the language
if ( v = $( '.the-tagcloud' ).css( 'display' ) ) {
......@@ -39,14 +48,17 @@
else {
$( '#' + id ).after( r );
}
});
}
);
}
})( jQuery );
jQuery( document ).ready(function( $ ) {
jQuery( document ).ready(
function( $ ) {
// collect taxonomies - code partly copied from WordPress
var taxonomies = new Array();
$( '.categorydiv' ).each(function(){
$( '.categorydiv' ).each(
function(){
var this_id = $( this ).attr( 'id' ), taxonomyParts, taxonomy;
taxonomyParts = this_id.split( '-' );
......@@ -56,16 +68,18 @@ jQuery( document ).ready(function( $ ) {
// add our hidden field in the new category form - for each hierarchical taxonomy
// to set the language when creating a new category
$( '#' + taxonomy + '-add-submit' ).before( $( '<input />' )
.attr( 'type', 'hidden' )
$( '#' + taxonomy + '-add-submit' ).before(
$( '<input />' ).attr( 'type', 'hidden' )
.attr( 'id', taxonomy + '-lang' )
.attr( 'name', 'term_lang_choice' )
.attr( 'value', $( '.post_lang_choice' ).val() )
);
});
}
);
// ajax for changing the post's language in the languages metabox
$( '.post_lang_choice' ).change(function() {
$( '.post_lang_choice' ).change(
function() {
var value = $( this ).val();
var lang = $( this ).children( 'option[value="' + value + '"]' ).attr( 'lang' );
var dir = $( '.pll-translation-column > span[lang="' + lang + '"]' ).attr( 'dir' );
......@@ -79,84 +93,111 @@ jQuery( document ).ready(function( $ ) {
_pll_nonce: $( '#_pll_nonce' ).val()
}
$.post( ajaxurl, data , function( response ) {
$.post(
ajaxurl,
data,
function( response ) {
var res = wpAjax.parseAjaxResponse( response, 'ajax-response' );
$.each( res.responses, function() {
$.each(
res.responses,
function() {
switch ( this.what ) {
case 'translations': // translations fields
$( '.translations' ).html( this.data );
// Data is built and come from server side and is well escaped when necessary
$( '.translations' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
init_translations();
break;
case 'taxonomy': // categories metabox for posts
var tax = this.data;
$( '#' + tax + 'checklist' ).html( this.supplemental.all );
$( '#' + tax + 'checklist-pop' ).html( this.supplemental.populars );
// @see wp_terms_checklist https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/template.php#L175
// @see https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/class-walker-category-checklist.php#L89-L111
$( '#' + tax + 'checklist' ).html( this.supplemental.all ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
// @see wp_popular_terms_checklist https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/template.php#L236
$( '#' + tax + 'checklist-pop' ).html( this.supplemental.populars ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
$( '#new' + tax + '_parent' ).replaceWith( this.supplemental.dropdown );
$( '#' + tax + '-lang' ).val( $( '.post_lang_choice' ).val() ); // hidden field
break;
case 'pages': // parent dropdown list for pages
$( '#parent_id' ).html( this.data );
// @see wp_dropdown_pages https://github.com/WordPress/WordPress/blob/5.2.2/wp-includes/post-template.php#L1186-L1208
// @see https://github.com/WordPress/WordPress/blob/5.2.2/wp-includes/class-walker-page-dropdown.php#L88
$( '#parent_id' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
break;
case 'flag': // flag in front of the select dropdown
$( '.pll-select-flag' ).html( this.data );
// Data is built and come from server side and is well escaped when necessary
$( '.pll-select-flag' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
break;
case 'permalink': // Sample permalink
var div = $( '#edit-slug-box' );
if ( '-1' != this.data && div.children().length ) {
div.html( this.data );
// @see get_sample_permalink_html https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/post.php#L1425-L1454
div.html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
}
break;
}
});
}
);
// modifies the language in the tag cloud
$( '.tagcloud-link' ).each(function() {
$( '.tagcloud-link' ).each(
function() {
var id = $( this ).attr( 'id' );
tagBox.get( id );
});
}
);
// Modifies the text direction
$( 'body' ).removeClass( 'pll-dir-rtl' ).removeClass( 'pll-dir-ltr' ).addClass( 'pll-dir-' + dir );
$( '#content_ifr' ).contents().find( 'html' ).attr( 'lang', lang ).attr( 'dir', dir );
$( '#content_ifr' ).contents().find( 'body' ).attr( 'dir', dir );
});
});
}
);
}
);
// translations autocomplete input box
function init_translations() {
$( '.tr_lang' ).each(function(){
$( '.tr_lang' ).each(
function(){
var tr_lang = $( this ).attr( 'id' ).substring( 8 );
var td = $( this ).parent().parent().siblings( '.pll-edit-column' );
$( this ).autocomplete({
$( 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 );
// ui.item.link is built and come from server side and is well escaped when necessary
td.html( ui.item.link ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
},
});
}
);
// when the input box is emptied
$( this ).blur(function() {
$( this ).blur(
function() {
if ( ! $( this ).val() ) {
$( '#htr_lang_' + tr_lang ).val( 0 );
td.html( td.siblings( '.hidden' ).children().clone() );
// Value is retrieved from HTML already generated server side
td.html( td.siblings( '.hidden' ).children().clone() ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
}
});
});
}
);
}
);
}
init_translations();
// Handle the response to a click on a Languages metabox button
$( '#ml_box' ).on( 'click', '.pll-button', function(){
$( '#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();
......@@ -169,14 +210,23 @@ jQuery( document ).ready(function( $ ) {
_pll_nonce: $( '#_pll_nonce' ).val()
}
$.post( ajaxurl, data , function( response ){
$.post(
ajaxurl,
data,
function( response ){
var res = wpAjax.parseAjaxResponse( response, 'ajax-response' );
$.each( res.responses, function() {
$.each(
res.responses,
function() {
id = id.replace( '[', '\\[' ).replace( ']', '\\]' );
$( '#' + id ).toggleClass( 'wp-ui-text-highlight' ).attr( 'title', this.data ).children( 'span' ).html( this.data );
$( '#' + id ).toggleClass( 'wp-ui-text-highlight' ).attr( 'title', this.data ).children( 'span' ).text( this.data );
$( 'input[name="' + id + '"]' ).val( ! data['value'] );
});
});
}
});
});
);
}
);
}
}
);
}
);
!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( $ ) {
$( '#update-nav-menu' ).bind( 'click', function( e ) {
jQuery( document ).ready(
function( $ ) {
$( '#update-nav-menu' ).bind(
'click',
function( e ) {
if ( e.target && e.target.className && -1 != e.target.className.indexOf( 'item-edit' ) ) {
$( "input[value='#pll_switcher'][type=text]" ).parent().parent().parent().each(function(){
$( "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
// pll_data is built server side with i18n strings without HTML and data retrieved from post meta
// the usage of attr method is safe before append call.
h = $( '<input>' ).attr(
{
type: 'hidden',
id: 'edit-menu-item-title-' + item,
name: 'menu-item-title[' + item + ']',
value: pll_data.title
});
$( this ).append( h );
}
);
$( this ).append( h ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
h = $( '<input>' ).attr({
h = $( '<input>' ).attr(
{
type: 'hidden',
id: 'edit-menu-item-url-' + item,
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
h = $( '<input>' ).attr({
h = $( '<input>' ).attr(
{
type: 'hidden',
id: 'edit-menu-item-pll-detect-' + item,
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
// 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' );
$( this ).prepend( p );
// item is a number part of id of parent menu item built by WordPress
// pll_data is built server side with i18n strings without HTML
label = $( '<label>' ).attr( 'for', 'edit-menu-item-' + ids[ i ] + '-' + item ).text( ' ' + pll_data.strings[ ids[ i ] ] );
p.append( label );
cb = $( '<input>' ).attr({
p.append( label ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
cb = $( '<input>' ).attr(
{
type: 'checkbox',
id: 'edit-menu-item-' + ids[ i ] + '-' + item,
name: 'menu-item-' + ids[ i ] + '[' + item + ']',
value: 1
});
}
);
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
$( '.menu-item-data-object-id' ).each(function() {
$( '.menu-item-data-object-id' ).each(
function() {
var id = $( this ).val();
var options = ['names-', 'flags-'];
$.each( options, function( i, v ) {
$( '#edit-menu-item-show_' + v + id ).change(function() {
$.each(
options,
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
/**
* Tag suggest in quick edit
*/
(function( $ ){
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
$.ajaxPrefilter(
function( options, originalOptions, jqXHR ) {
if ( 'string' === typeof options.data && -1 !== options.data.indexOf( 'action=ajax-tag-search' ) && ( lang = $( ':input[name="inline_lang_choice"]' ).val() ) ) {
options.data = 'lang=' + lang + '&' + options.data;
}
});
}
);
})( jQuery );
/**
* Quick edit
*/
(function( $ ) {
$( document ).bind( 'DOMNodeInserted', function( e ) {
$( document ).bind(
'DOMNodeInserted',
function( e ) {
var t = $( e.target );
// WP inserts the quick edit from
......@@ -30,39 +35,57 @@
filter_pages( lang ); // initial filter for parent dropdown
// modify category checklist an parent dropdown on language change
select.change(function() {
select.change(
function() {
filter_terms( $( this ).val() );
filter_pages( $( this ).val() );
});
}
);
}
}
// filter category checklist
function filter_terms( lang ) {
if ( "undefined" != typeof( pll_term_languages ) ) {
$.each( pll_term_languages, function( lg, term_tax ) {
$.each( term_tax, function( tax, terms ) {
$.each( terms, function( i ) {
$.each(
pll_term_languages,
function( lg, term_tax ) {
$.each(
term_tax,
function( tax, terms ) {
$.each(
terms,
function( i ) {
id = '#' + tax + '-' + pll_term_languages[ lg ][ tax ][ i ];
lang == lg ? $( id ).show() : $( id ).hide();
});
});
});
}
);
}
);
}
);
}
}
// filter parent page dropdown list
function filter_pages( lang ) {
if ( "undefined" != typeof( pll_page_languages ) ) {
$.each( pll_page_languages, function( lg, pages ) {
$.each( pages, function( i ) {
$.each(
pll_page_languages,
function( lg, pages ) {
$.each(
pages,
function( i ) {
v = $( '#post_parent option[value="' + pll_page_languages[ lg ][ i ] + '"]' );
lang == lg ? v.show() : v.hide();
});
});
}
);
}
);
}
});
}
}
);
})( jQuery );
/**
......@@ -70,13 +93,16 @@
* Acts on ajaxSuccess event
*/
(function( $ ) {
$( document ).ajaxSuccess(function( event, xhr, settings ) {
$( document ).ajaxSuccess(
function( event, xhr, settings ) {
function update_rows( post_id ) {
// collect old translations
var translations = new Array;
$( '.translation_' + post_id ).each(function() {
var translations = new Array();
$( '.translation_' + post_id ).each(
function() {
translations.push( $( this ).parent().parent().attr( 'id' ).substring( 5 ) );
});
}
);
var data = {
action: 'pll_update_post_rows',
......@@ -85,19 +111,26 @@
post_type: $( "input[name='post_type']" ).val(),
screen: $( "input[name='screen']" ).val(),
_pll_nonce: $( "input[name='_inline_edit']" ).val() // reuse quick edit nonce
}
};
// get the modified rows in ajax and update them
$.post( ajaxurl, data, function( response ) {
$.post(
ajaxurl,
data,
function( response ) {
if ( response ) {
var res = wpAjax.parseAjaxResponse( response, 'ajax-response' );
$.each( res.responses, function() {
$.each(
res.responses,
function() {
if ( 'row' == this.what ) {
$( "#post-" + this.supplemental.post_id ).replaceWith( this.data );
}
});
}
});
);
}
}
);
}
if ( 'string' == typeof( settings.data ) ) { // Need to check the type due to block editor sometime sending FormData objects
......@@ -106,7 +139,8 @@
update_rows( data['post_ID'] );
}
}
});
}
);
})( jQuery );
/**
......@@ -114,25 +148,30 @@
* When clicking on attach link, filters find post list per media language
*/
(function( $ ){
$.ajaxPrefilter( function ( options, originalOptions, jqXHR ) {
$.ajaxPrefilter(
function ( options, originalOptions, jqXHR ) {
if ( 'string' === typeof options.data && -1 !== options.data.indexOf( 'action=find_posts' ) ) {
options.data = 'pll_post_id=' + $( '#affected' ).val() + '&' + options.data;
}
});
})( jQuery )
}
);
})( jQuery );
/**
* Bulk translate
*/
jQuery( document ).ready( function( $ ) {
jQuery( document ).ready(
function( $ ) {
var t = this;
$( '.editinline' ).click( function(){
$( '.editinline' ).click(
function(){
$( '#pll-translate' ).find( '.cancel' ).click(); // Close the form on quick edit
} );
}
);
$( '#doaction, #doaction2' ).click( function( e ){
$( '#doaction, #doaction2' ).click(
function( e ){
t.whichBulkButtonId = $( this ).attr( 'id' );
var n = t.whichBulkButtonId.substr( 2 );
......@@ -146,29 +185,53 @@ jQuery( document ).ready( function( $ ) {
$( '#pll-translate td' ).attr( 'colspan', $( 'th:visible, td:visible', '.widefat:first thead' ).length );
$( 'table.widefat tbody' ).prepend( $( '#pll-translate' ) ).prepend( '<tr class="hidden"></tr>' ); // The hidden tr allows to keep the background color
} else {
$( '#pll-translate' ).find( '.cancel' ).click(); // Close the form on any other bulk action
$( '#pll-translate' ).find( '.cancel' ).click();
}
}
} );
);
// Cancel
$( '#pll-translate' ).on( 'click', '.cancel', function(){
$( '#pll-translate' ).on(
'click',
'.cancel',
function(){
// Close the form on any other bulk action
$( '#pll-translate' ).siblings( '.hidden' ).remove();
$( '#pll-bulk-translate' ).append( $( '#pll-translate' ) );
// #pll-translate is built and come from server side and is well escaped when necessary
$( '#pll-bulk-translate' ).append( $( '#pll-translate' ) ); //phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
// Move focus back to the Bulk Action button that was activated.
$( '#' + t.whichBulkButtonId ).focus();
} );
}
);
// Act when pressing enter or esc
$( '#pll-translate' ).keydown( function( event ){
$( '#pll-translate' ).keydown(
function( event ){
if ( 13 === event.keyCode && ! $( event.target ).hasClass( 'cancel' ) ) {
event.preventDefault();
$( this ).find( 'input[type=submit]' ).click();
}
if ( 27 === event.keyCode ) {
event.preventDefault();
$( this ).find( '.cancel' ).click();
}
} );
} );
}
);
// Clean DOM in case of file download
$( '#posts-filter' ).on(
'submit',
function() {
$( '.settings-error' ).remove();
setTimeout(
function() {
$( 'input[type=checkbox]:checked' ).attr( 'checked', false );
$( '#pll-translate' ).find( '.cancel' ).trigger( 'click' );
},
500
);
}
);
}
);
!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)})});
// quick edit
(function( $ ) {
$( document ).bind( 'DOMNodeInserted', function( e ) {
$( document ).bind(
'DOMNodeInserted',
function( e ) {
var t = $( e.target );
// WP inserts the quick edit from
......@@ -20,20 +22,24 @@
}
}
}
});
}
);
})( jQuery );
// update rows of translated terms when adding / deleting a translation or when the language is modified in quick edit
// acts on ajaxSuccess event
(function( $ ) {
$( document ).ajaxSuccess(function( event, xhr, settings ) {
$( document ).ajaxSuccess(
function( event, xhr, settings ) {
function update_rows( term_id ) {
// collect old translations
var translations = new Array;
$( '.translation_' + term_id ).each(function() {
var translations = new Array();
$( '.translation_' + term_id ).each(
function() {
translations.push( $( this ).parent().parent().attr( 'id' ).substring( 4 ) );
});
}
);
var data = {
action: 'pll_update_term_rows',
......@@ -43,19 +49,26 @@
post_type: $( "input[name='post_type']" ).val(),
screen: $( "input[name='screen']" ).val(),
_pll_nonce: $( '#_pll_nonce' ).val()
}
};
// get the modified rows in ajax and update them
$.post( ajaxurl, data, function( response ) {
$.post(
ajaxurl,
data,
function( response ) {
if ( response ) {
var res = wpAjax.parseAjaxResponse( response, 'ajax-response' );
$.each( res.responses, function() {
$.each(
res.responses,
function() {
if ( 'row' == this.what ) {
$( "#tag-" + this.supplemental.term_id ).replaceWith( this.data );
}
});
}
});
);
}
}
);
}
var data = wpAjax.unserialize( settings.data ); // what were the data sent by the ajax request?
......@@ -64,11 +77,14 @@
// when adding a term, the new term_id is in the ajax response
case 'add-tag':
res = wpAjax.parseAjaxResponse( xhr.responseXML, 'ajax-response' );
$.each( res.responses, function() {
$.each(
res.responses,
function() {
if ( 'term' == this.what ) {
update_rows( this.supplemental.term_id );
}
});
}
);
// and also reset translations hidden input fields
$( '.htr_lang' ).val( 0 );
......@@ -85,19 +101,22 @@
break;
}
}
});
}
);
})( jQuery );
jQuery( document ).ready(function( $ ) {
jQuery( document ).ready(
function( $ ) {
// translations autocomplete input box
function init_translations() {
$( '.tr_lang' ).each(function(){
$( '.tr_lang' ).each(
function(){
var tr_lang = $( this ).attr( 'id' ).substring( 8 );
var td = $( this ).parent().parent().siblings( '.pll-edit-column' );
$( this ).autocomplete({
$( this ).autocomplete(
{
minLength: 0,
source: ajaxurl + '?action=pll_terms_not_translated' +
'&term_language=' + $( '#term_lang_choice' ).val() +
'&term_id=' + $( "input[name='tag_ID']" ).val() +
......@@ -105,27 +124,33 @@ jQuery( document ).ready(function( $ ) {
'&translation_language=' + tr_lang +
'&post_type=' + typenow +
'&_pll_nonce=' + $( '#_pll_nonce' ).val(),
select: function( event, ui ) {
$( '#htr_lang_' + tr_lang ).val( ui.item.id );
td.html( ui.item.link );
// ui.item.link is built and come from server side and is well escaped when necessary
td.html( ui.item.link ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
},
});
}
);
// when the input box is emptied
$( this ).blur(function() {
$( this ).blur(
function() {
if ( ! $( this ).val() ) {
$( '#htr_lang_' + tr_lang ).val( 0 );
td.html( td.siblings( '.hidden' ).children().clone() );
// Value is retrieved from HTML already generated server side
td.html( td.siblings( '.hidden' ).children().clone() ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
}
}
});
});
);
}
);
}
init_translations();
// ajax for changing the term's language
$( '#term_lang_choice' ).change(function() {
$( '#term_lang_choice' ).change(
function() {
var value = $( this ).val();
var lang = $( this ).children( 'option[value="' + value + '"]' ).attr( 'lang' );
var dir = $( '.pll-translation-column > span[lang="' + lang + '"]' ).attr( 'dir' );
......@@ -138,14 +163,20 @@ jQuery( document ).ready(function( $ ) {
taxonomy: $( "input[name='taxonomy']" ).val(),
post_type: typenow,
_pll_nonce: $( '#_pll_nonce' ).val()
}
};
$.post( ajaxurl, data, function( response ) {
$.post(
ajaxurl,
data,
function( response ) {
var res = wpAjax.parseAjaxResponse( response, 'ajax-response' );
$.each( res.responses, function() {
$.each(
res.responses,
function() {
switch ( this.what ) {
case 'translations': // translations fields
$( "#term-translations" ).html( this.data );
// Data is built and come from server side and is well escaped when necessary
$( "#term-translations" ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
init_translations();
break;
case 'parent': // parent dropdown list for hierarchical taxonomies
......@@ -155,13 +186,18 @@ jQuery( document ).ready(function( $ ) {
$( '.tagcloud' ).replaceWith( this.data );
break;
case 'flag': // flag in front of the select dropdown
$( '.pll-select-flag' ).html( this.data );
// Data is built and come from server side and is well escaped when necessary
$( '.pll-select-flag' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
break;
}
});
}
);
// Modifies the text direction
$( 'body' ).removeClass( 'pll-dir-rtl' ).removeClass( 'pll-dir-ltr' ).addClass( 'pll-dir-' + dir );
});
});
});
}
);
}
);
}
);
!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(
function( $ ) {
// biography
// FIXME there is probably a more efficient way to do this
var td = $( '#description' ).parent();
......@@ -6,15 +7,21 @@ jQuery( document ).ready(function( $ ) {
var span = td.children( '.description' ).clone();
td.children().remove();
$( '.biography' ).each(function(){
$( '.biography' ).each(
function(){
lang = $( this ).attr( 'name' ).split( '___' );
desc = d.clone();
desc.attr( 'name', 'description_' + lang[0] );
desc.html( $( this ).val() );
td.append( '<div>' + lang[1] + '</div' );
td.append( desc );
});
desc.attr( 'id', 'description_' + lang[0] );
// 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( 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(
function( $ ) {
var widgets_container, widgets_selector, flags;
if ( 'undefined' !== typeof pll_widgets && pll_widgets.hasOwnProperty( 'flags' ) ) {
......@@ -7,6 +8,7 @@ jQuery( function( $ ) {
/**
* Prepend widget titles with a flag once a language is selected.
*
* @param {object} widget The widget element.
* @return {void} Nothing.
*/
......@@ -17,15 +19,16 @@ jQuery( function( $ ) {
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 ) {
icon += ' &nbsp; ';
var current = $( '.pll-lang', title );
if ( current.length ) {
current.html( icon );
current.html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
} else {
flag = '<span class="pll-lang">' + icon + '</span>';
flag = $( '<span />' ).addClass( 'pll-lang' ).html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
title.prepend( flag );
}
} else {
......@@ -71,13 +74,20 @@ jQuery( function( $ ) {
}
// Add flags on load.
$( widgets_selector, widgets_container ).each( function() {
$( widgets_selector, widgets_container ).each(
function() {
add_flag( this );
} );
}
);
// Update flags.
widgets_container.on( 'change', '.pll-lang-choice', function() {
widgets_container.on(
'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 {
* @since 1.7.7
*/
public function init() {
$options = get_option( 'polylang' );
// The Lingotek tab
add_filter( 'pll_settings_tabs', array( $this, 'add_tab' ) );
add_action( 'pll_settings_active_tab_lingotek', array( $this, 'display_tab' ) );
......@@ -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' );
$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' ),
__( 'Learn more', 'polylang' )
);
......@@ -39,7 +37,7 @@ class PLL_Lingotek {
$content .= ' ' . __( 'Click on Activate Lingotek to start translating.', 'polylang' );
$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,
__( 'Activate Lingotek', 'polylang' )
) . $buttons;
......
......@@ -61,7 +61,7 @@ class PLL_Featured_Content {
$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;
}
......
......@@ -266,12 +266,20 @@ class PLL_Plugins_Compat {
* @since 2.0.10
*/
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' ) ) {
if ( function_exists( 'twentyseventeen_panel_count' ) && PLL() instanceof PLL_Frontend ) {
$num_sections = twentyseventeen_panel_count();
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 {
protected function remap_terms_relations( &$terms ) {
global $wpdb;
$trs = array();
foreach ( $terms as $term ) {
$translations = maybe_unserialize( $term['term_description'] );
foreach ( $translations as $slug => $old_id ) {
......@@ -161,6 +163,8 @@ class PLL_WP_Import extends WP_Import {
protected function remap_translations( &$terms, &$processed_objects ) {
global $wpdb;
$u = array();
foreach ( $terms as $term ) {
$translations = maybe_unserialize( $term['term_description'] );
$new_translations = array();
......
......@@ -189,7 +189,7 @@ class PLL_Admin_Sync extends PLL_Sync {
if ( is_object( $this->$obj ) && method_exists( $this->$obj, 'copy' ) ) {
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
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions
......@@ -205,7 +205,7 @@ class PLL_Admin_Sync extends PLL_Sync {
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
sprintf(
'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 {
* @param array $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
}
......
......@@ -359,8 +359,6 @@ abstract class PLL_Sync_Metas {
* @param array $translations The list of translations object ids
*/
public function save_object( $object_id, $obj, $translations ) {
$src_lang = array_search( $object_id, $translations );
foreach ( $translations as $tr_lang => $tr_id ) {
if ( $tr_id != $object_id ) {
$this->copy( $object_id, $tr_id, $tr_lang, true );
......
......@@ -83,7 +83,6 @@ class PLL_Sync {
public function can_sync_post_parent( $post_parent, $post_id, $postarr ) {
if ( ! empty( $postarr['ID'] ) && ! $this->model->post->current_user_can_synchronize( $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 ) {
if ( $tr_id !== $postarr['ID'] && $post = get_post( $tr_id ) ) {
$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 licenses step
*
* @since 2.7
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Don't access directly.
};
$licenses = apply_filters( 'pll_settings_licenses', array() );
$is_error = isset( $_GET['activate_error'] ) && 'i18n_license_key_error' === sanitize_key( $_GET['activate_error'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
?>
<p>
<?php esc_html_e( 'You are using plugins which require a license key.', 'polylang' ); ?>
<?php echo esc_html( _n( 'Please enter your license key:', 'Please enter your license keys:', count( $licenses ), 'polylang' ) ); ?>
</p>
<h2><?php esc_html_e( 'Licenses', 'polylang' ); ?></h2>
<div id="messages">
<?php if ( $is_error ) : ?>
<p class="error"><?php esc_html_e( 'There is an error with a license key.', 'polylang' ); ?></p>
<?php endif; ?>
</div>
<div class="form-field">
<table id="pll-licenses-table" class="form-table">
<tbody>
<?php
foreach ( $licenses as $license ) {
// Escaping is already done in get_form_field method.
echo $license->get_form_field(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
?>
</tbody>
</table>
</div>
<?php
/**
* Displays the wizard unstranslated content step
*
* @since 2.7
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Don't access directly.
};
$languages_list = $this->model->get_languages_list();
$default_language = ! empty( $languages_list ) ? $this->options['default_lang'] : '';
?>
<h2><?php esc_html_e( 'Content without language', 'polylang' ); ?></h2>
<p>
<?php esc_html_e( 'There are posts, pages, categories or tags without language.', 'polylang' ); ?><br />
<?php esc_html_e( 'For your site to work correctly, you need to assign a language to all your contents.', 'polylang' ); ?><br />
<?php esc_html_e( 'The selected language below will be applied to all your content without an assigned language.', 'polylang' ); ?>
</p>
<div class="form-field">
<label for="lang_list"><?php esc_html_e( 'Choose the language to be assigned', 'polylang' ); ?></label>
<select name="language" id="lang_list">
<?php
foreach ( $languages_list as $lg ) {
printf(
'<option value="%1$s" data-flag-html="%3$s" data-language-name="%2$s"%4$s>%2$s - %1$s</option>' . "\n",
esc_attr( $lg->locale ),
esc_html( $lg->name ),
esc_html( $lg->flag ),
$lg->slug === $default_language ? ' selected="selected"' : ''
);
}
?>
</select>
</div>
This diff is collapsed.
......@@ -3,7 +3,7 @@
/**
Plugin Name: Polylang
Plugin URI: https://polylang.pro
Version: 2.6.10
Version: 2.7.1
Author: WP SYNTEX
Author uri: https://polylang.pro
Description: Adds multilingual capability to WordPress
......@@ -51,8 +51,8 @@ if ( defined( 'POLYLANG_BASENAME' ) ) {
}
} else {
// Go on loading the plugin
define( 'POLYLANG_VERSION', '2.6.10' );
define( 'PLL_MIN_WP_VERSION', '4.7' );
define( 'POLYLANG_VERSION', '2.7.1' );
define( 'PLL_MIN_WP_VERSION', '4.9' );
define( 'PLL_MIN_PHP_VERSION', '5.6' );
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