Polylang - Version 2.3.8

Version Description

(2018-07-16) =

  • Pro: Duplicate term meta when duplicating a post creates new terms
  • Pro: Add compatibility with ACF Pro when it's bundled with the theme
  • Pro: Fix a fatal error when duplicating posts
  • Set cookie during the home redirect
  • Accept a port in the url to detect the site home
  • Add filter 'pll_is_cache_active' to allow to load the cache compatibility #270 #274
  • Fix potential fatal error when a 3rd party misuses the 'wpml_active_languages' filter #268
  • Fix Uncaught TypeError: s.split is not a function. Props Wouter Van Vliet #262
  • Fix text alignment for RTL scripts in Lingotek panel #247
  • Fix html language attribute filter on admin
  • Fix cookie expiration time when set in js. Props Jens Nachtigall #271
  • Fix fatal error when a 3rd party misuses the WP_Query tax_query param. Props JanneAalto #252
  • Fix an edge case which could mess home pages on a multisite
Download this release

Release Info

Developer Chouby
Plugin Icon 128x128 Polylang
Version 2.3.8
Comparing to
See all releases

Code changes from version 2.3.7 to 2.3.8

admin/admin-base.php CHANGED
@@ -158,38 +158,38 @@ class PLL_Admin_Base extends PLL_Base {
158
 
159
  $str = http_build_query( $params );
160
  $arr = json_encode( $params );
161
- ?>
162
- <script type="text/javascript">
163
- if (typeof jQuery != 'undefined') {
164
- (function($){
165
- $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
166
- if ( -1 != options.url.indexOf( ajaxurl ) || -1 != ajaxurl.indexOf( options.url ) ) {
167
- if ( 'undefined' === typeof options.data ) {
168
- options.data = ( 'get' === options.type.toLowerCase() ) ? '<?php echo $str; ?>' : <?php echo $arr; ?>;
169
- } else {
170
- if ( 'string' === typeof options.data ) {
171
- if ( '' === options.data && 'get' === options.type.toLowerCase() ) {
172
- options.url = options.url+'&<?php echo $str; ?>';
173
  } else {
174
- try {
175
- o = $.parseJSON(options.data);
176
- o = $.extend(o, <?php echo $arr; ?>);
177
- options.data = JSON.stringify(o);
178
- }
179
- catch(e) {
180
- options.data = '<?php echo $str; ?>&'+options.data;
 
 
 
 
 
 
 
 
181
  }
182
  }
183
- } else {
184
- options.data = $.extend(options.data, <?php echo $arr; ?>);
185
  }
186
- }
187
- }
188
- });
189
- })(jQuery)
190
- }
191
- </script>
192
- <?php
193
  }
194
 
195
  /**
158
 
159
  $str = http_build_query( $params );
160
  $arr = json_encode( $params );
161
+ ?>
162
+ <script type="text/javascript">
163
+ if (typeof jQuery != 'undefined') {
164
+ (function($){
165
+ $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
166
+ if ( -1 != options.url.indexOf( ajaxurl ) || -1 != ajaxurl.indexOf( options.url ) ) {
167
+ if ( 'undefined' === typeof options.data ) {
168
+ options.data = ( 'get' === options.type.toLowerCase() ) ? '<?php echo $str; ?>' : <?php echo $arr; ?>;
 
 
 
 
169
  } else {
170
+ if ( 'string' === typeof options.data ) {
171
+ if ( '' === options.data && 'get' === options.type.toLowerCase() ) {
172
+ options.url = options.url+'&<?php echo $str; ?>';
173
+ } else {
174
+ try {
175
+ var o = $.parseJSON(options.data);
176
+ o = $.extend(o, <?php echo $arr; ?>);
177
+ options.data = JSON.stringify(o);
178
+ }
179
+ catch(e) {
180
+ options.data = '<?php echo $str; ?>&'+options.data;
181
+ }
182
+ }
183
+ } else {
184
+ options.data = $.extend(options.data, <?php echo $arr; ?>);
185
  }
186
  }
 
 
187
  }
188
+ });
189
+ })(jQuery)
190
+ }
191
+ </script>
192
+ <?php
 
 
193
  }
194
 
195
  /**
admin/admin-filters-term.php CHANGED
@@ -32,7 +32,7 @@ class PLL_Admin_Filters_Term {
32
  add_action( $tax . '_edit_form_fields', array( $this, 'edit_term_form' ) );
33
 
34
  // Adds action related to languages when deleting categories and post tags
35
- add_action( 'delete_' . $tax, array( $this, 'delete_term' ) );
36
  }
37
 
38
  // Adds actions related to languages when creating or saving categories and post tags
32
  add_action( $tax . '_edit_form_fields', array( $this, 'edit_term_form' ) );
33
 
34
  // Adds action related to languages when deleting categories and post tags
35
+ add_action( 'pre_delete_term', array( $this, 'delete_term' ) );
36
  }
37
 
38
  // Adds actions related to languages when creating or saving categories and post tags
frontend/choose-lang-url.php CHANGED
@@ -26,29 +26,29 @@ class PLL_Choose_Lang_Url extends PLL_Choose_lang {
26
  }
27
 
28
  /**
29
- * finds the language according to information found in the url
30
  *
31
  * @since 1.2
32
  */
33
  public function set_language_from_url() {
34
- $host = str_replace( 'www.', '', parse_url( $this->links_model->home, PHP_URL_HOST ) );
35
  $home_path = parse_url( $this->links_model->home, PHP_URL_PATH );
36
 
37
- $requested_host = str_replace( 'www.', '', $_SERVER['HTTP_HOST'] );
38
- $requested_uri = rtrim( str_replace( $this->index, '', $_SERVER['REQUEST_URI'] ), '/' ); // some PHP setups turn requests for / into /index.php in REQUEST_URI
39
 
40
- // home is requested
41
  if ( $requested_host == $host && $requested_uri == $home_path && empty( $_SERVER['QUERY_STRING'] ) ) {
42
  $this->home_language();
43
  add_action( 'setup_theme', array( $this, 'home_requested' ) );
44
  }
45
 
46
- // take care to post & page preview http://wordpress.org/support/topic/static-frontpage-url-parameter-url-language-information
47
  elseif ( isset( $_GET['preview'] ) && ( ( isset( $_GET['p'] ) && $id = (int) $_GET['p'] ) || ( isset( $_GET['page_id'] ) && $id = (int) $_GET['page_id'] ) ) ) {
48
  $curlang = ( $lg = $this->model->post->get_language( $id ) ) ? $lg : $this->model->get_language( $this->options['default_lang'] );
49
  }
50
 
51
- // take care to ( unattached ) attachments
52
  elseif ( isset( $_GET['attachment_id'] ) && $id = (int) $_GET['attachment_id'] ) {
53
  $curlang = ( $lg = $this->model->post->get_language( $id ) ) ? $lg : $this->get_preferred_language();
54
  }
@@ -61,8 +61,8 @@ class PLL_Choose_Lang_Url extends PLL_Choose_lang {
61
  $curlang = $this->model->get_language( $this->options['default_lang'] );
62
  }
63
 
64
- // if no language found, check_language_code_in_url will attempt to find one and redirect to the correct url
65
- // otherwise 404 will be fired in the preferred language
66
  $this->set_language( empty( $curlang ) ? $this->get_preferred_language() : $curlang );
67
  }
68
 
26
  }
27
 
28
  /**
29
+ * Finds the language according to information found in the url
30
  *
31
  * @since 1.2
32
  */
33
  public function set_language_from_url() {
34
+ $host = str_replace( 'www.', '', parse_url( $this->links_model->home, PHP_URL_HOST ) ); // Remove www. for the comparison
35
  $home_path = parse_url( $this->links_model->home, PHP_URL_PATH );
36
 
37
+ $requested_host = parse_url( 'http://' . str_replace( 'www.', '', $_SERVER['HTTP_HOST'] ), PHP_URL_HOST ); // Remove the port and www. for the comparison
38
+ $requested_uri = rtrim( str_replace( $this->index, '', $_SERVER['REQUEST_URI'] ), '/' ); // Some PHP setups turn requests for / into /index.php in REQUEST_URI
39
 
40
+ // Home is requested
41
  if ( $requested_host == $host && $requested_uri == $home_path && empty( $_SERVER['QUERY_STRING'] ) ) {
42
  $this->home_language();
43
  add_action( 'setup_theme', array( $this, 'home_requested' ) );
44
  }
45
 
46
+ // Take care to post & page preview http://wordpress.org/support/topic/static-frontpage-url-parameter-url-language-information
47
  elseif ( isset( $_GET['preview'] ) && ( ( isset( $_GET['p'] ) && $id = (int) $_GET['p'] ) || ( isset( $_GET['page_id'] ) && $id = (int) $_GET['page_id'] ) ) ) {
48
  $curlang = ( $lg = $this->model->post->get_language( $id ) ) ? $lg : $this->model->get_language( $this->options['default_lang'] );
49
  }
50
 
51
+ // Take care to ( unattached ) attachments
52
  elseif ( isset( $_GET['attachment_id'] ) && $id = (int) $_GET['attachment_id'] ) {
53
  $curlang = ( $lg = $this->model->post->get_language( $id ) ) ? $lg : $this->get_preferred_language();
54
  }
61
  $curlang = $this->model->get_language( $this->options['default_lang'] );
62
  }
63
 
64
+ // If no language found, check_language_code_in_url() will attempt to find one and redirect to the correct url
65
+ // Otherwise a 404 will be fired in the preferred language
66
  $this->set_language( empty( $curlang ) ? $this->get_preferred_language() : $curlang );
67
  }
68
 
frontend/choose-lang.php CHANGED
@@ -74,15 +74,16 @@ abstract class PLL_Choose_Lang {
74
  }
75
 
76
  /**
77
- * set a cookie to remember the language.
78
- * possibility to set PLL_COOKIE to false will disable cookie although it will break some functionalities
79
  *
80
  * @since 1.5
81
  */
82
  public function maybe_setcookie() {
83
- // check headers have not been sent to avoid ugly error
84
- // cookie domain must be set to false for localhost ( default value for COOKIE_DOMAIN ) thanks to Stephen Harris.
85
- if ( ! headers_sent() && PLL_COOKIE !== false && ! empty( $this->curlang ) && ( ! isset( $_COOKIE[ PLL_COOKIE ] ) || $_COOKIE[ PLL_COOKIE ] != $this->curlang->slug ) && ! is_404() ) {
 
86
 
87
  /**
88
  * Filter the Polylang cookie duration
@@ -260,6 +261,7 @@ abstract class PLL_Choose_Lang {
260
  * @param string $redirect the url the visitor will be redirected to
261
  */
262
  if ( $redirect = apply_filters( 'pll_redirect_home', $redirect ) ) {
 
263
  wp_redirect( $redirect );
264
  exit;
265
  }
74
  }
75
 
76
  /**
77
+ * Set a cookie to remember the language.
78
+ * Setting PLL_COOKIE to false will disable cookie although it will break some functionalities
79
  *
80
  * @since 1.5
81
  */
82
  public function maybe_setcookie() {
83
+ // Don't set cookie in javascript when a cache plugin is active
84
+ // Check headers have not been sent to avoid ugly error
85
+ // Cookie domain must be set to false for localhost ( default value for COOKIE_DOMAIN ) thanks to Stephen Harris.
86
+ if ( ! pll_is_cache_active() && ! headers_sent() && PLL_COOKIE !== false && ! empty( $this->curlang ) && ( ! isset( $_COOKIE[ PLL_COOKIE ] ) || $_COOKIE[ PLL_COOKIE ] != $this->curlang->slug ) && ! is_404() ) {
87
 
88
  /**
89
  * Filter the Polylang cookie duration
261
  * @param string $redirect the url the visitor will be redirected to
262
  */
263
  if ( $redirect = apply_filters( 'pll_redirect_home', $redirect ) ) {
264
+ $this->maybe_setcookie();
265
  wp_redirect( $redirect );
266
  exit;
267
  }
frontend/frontend-static-pages.php CHANGED
@@ -71,8 +71,8 @@ class PLL_Frontend_Static_Pages extends PLL_Static_Pages {
71
  * @return int
72
  */
73
  public function translate_page_on_front( $v ) {
74
- // returns the current page if there is no translation to avoid ugly notices
75
- return isset( $this->curlang->page_on_front ) ? $this->curlang->page_on_front : $v;
76
  }
77
 
78
  /**
71
  * @return int
72
  */
73
  public function translate_page_on_front( $v ) {
74
+ // Don't attempt to translate in a 'switch_blog' action as there is a risk to call this function while initializing the languages cache
75
+ return isset( $this->curlang->page_on_front ) && ! doing_action( 'switch_blog' ) ? $this->curlang->page_on_front : $v;
76
  }
77
 
78
  /**
include/filters.php CHANGED
@@ -229,7 +229,7 @@ class PLL_Filters {
229
  * @return string
230
  */
231
  public function language_attributes( $output ) {
232
- if ( $language = $this->model->get_language( get_locale() ) ) {
233
  $output = str_replace( '"' . get_bloginfo( 'language' ) . '"', '"' . $language->get_locale( 'display' ) . '"', $output );
234
  }
235
  return $output;
229
  * @return string
230
  */
231
  public function language_attributes( $output ) {
232
+ if ( $language = $this->model->get_language( is_admin() ? get_user_locale() : get_locale() ) ) {
233
  $output = str_replace( '"' . get_bloginfo( 'language' ) . '"', '"' . $language->get_locale( 'display' ) . '"', $output );
234
  }
235
  return $output;
include/functions.php CHANGED
@@ -2,7 +2,8 @@
2
 
3
  /**
4
  * Define wordpress.com VIP equivalent of uncached functions
5
- * and WordPress backward compatibility functions
 
6
  */
7
 
8
  if ( ! function_exists( 'wpcom_vip_get_page_by_title' ) ) {
@@ -82,3 +83,22 @@ if ( ! function_exists( 'wp_doing_ajax' ) ) {
82
  return apply_filters( 'wp_doing_ajax', defined( 'DOING_AJAX' ) && DOING_AJAX );
83
  }
84
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  /**
4
  * Define wordpress.com VIP equivalent of uncached functions
5
+ * WordPress backward compatibility functions
6
+ * and miscellaneous utility functions
7
  */
8
 
9
  if ( ! function_exists( 'wpcom_vip_get_page_by_title' ) ) {
83
  return apply_filters( 'wp_doing_ajax', defined( 'DOING_AJAX' ) && DOING_AJAX );
84
  }
85
  }
86
+
87
+ /**
88
+ * Determines whether we should load the cache compatibility
89
+ *
90
+ * @since 2.3.8
91
+ *
92
+ * return bool True if the cache compatibility must be loaded
93
+ */
94
+ function pll_is_cache_active() {
95
+ /**
96
+ * Filters whether we should load the cache compatibility
97
+ *
98
+ * @since 2.3.8
99
+ *
100
+ * @bool $is_cache True if a known cache plugin is active
101
+ * incl. WP Fastest Cache which doesn't use WP_CACHE
102
+ */
103
+ return apply_filters( 'pll_is_cache_active', ( defined( 'WP_CACHE' ) && WP_CACHE ) || defined( 'WPFC_MAIN_PATH' ) );
104
+ }
include/query.php CHANGED
@@ -106,8 +106,14 @@ class PLL_Query {
106
  array( $tax_query ),
107
  'relation' => 'AND',
108
  );
109
- } else {
 
 
 
110
  $tax_query[] = $lang_query;
 
 
 
111
  }
112
  }
113
 
106
  array( $tax_query ),
107
  'relation' => 'AND',
108
  );
109
+ } elseif ( is_array( $tax_query ) ) {
110
+ // The tax query is expected to be *always* an array, but it seems that 3rd parties fill it with a string
111
+ // Causing a fatal error if we don't check it.
112
+ // See https://wordpress.org/support/topic/fatal-error-2947/
113
  $tax_query[] = $lang_query;
114
+ } elseif ( empty( $tax_query ) ) {
115
+ // Supposing the tax query has been wrongly filled with an empty string
116
+ $tax_query = array( $lang_query );
117
  }
118
  }
119
 
include/static-pages.php CHANGED
@@ -96,7 +96,7 @@ abstract class PLL_Static_Pages {
96
  * @return int
97
  */
98
  public function translate_page_for_posts( $v ) {
99
- // Returns the current page if there is no translation to avoid ugly notices
100
- return isset( $this->curlang->page_for_posts ) ? $this->curlang->page_for_posts : $v;
101
  }
102
  }
96
  * @return int
97
  */
98
  public function translate_page_for_posts( $v ) {
99
+ // Don't attempt to translate in a 'switch_blog' action as there is a risk to call this function while initializing the languages cache
100
+ return isset( $this->curlang->page_for_posts ) && ! doing_action( 'switch_blog' ) ? $this->curlang->page_for_posts : $v;
101
  }
102
  }
include/translated-object.php CHANGED
@@ -220,6 +220,7 @@ abstract class PLL_Translated_Object {
220
  * @return bool|int the translation post id or term id if exists, otherwise the post id or term id, false if the post has no language
221
  */
222
  public function get( $id, $lang ) {
 
223
  $obj_lang = $this->get_language( $id ); // FIXME is this necessary?
224
  if ( ! $lang || ! $obj_lang ) {
225
  return false;
220
  * @return bool|int the translation post id or term id if exists, otherwise the post id or term id, false if the post has no language
221
  */
222
  public function get( $id, $lang ) {
223
+ $id = (int) $id;
224
  $obj_lang = $this->get_language( $id ); // FIXME is this necessary?
225
  if ( ! $lang || ! $obj_lang ) {
226
  return false;
include/translated-term.php CHANGED
@@ -125,7 +125,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
125
  parent::delete_translation( $id );
126
  wp_delete_object_term_relationships( $id, 'term_translations' );
127
 
128
- if ( $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $wpdb->terms WHERE term_id = %d;", $id ) ) ) {
129
  // Always keep a group for terms to allow relationships remap when importing from a WXR file
130
  $translations[ $slug ] = $id;
131
  wp_insert_term( $group = uniqid( 'pll_' ), 'term_translations', array( 'description' => serialize( $translations ) ) );
125
  parent::delete_translation( $id );
126
  wp_delete_object_term_relationships( $id, 'term_translations' );
127
 
128
+ if ( ! doing_action( 'pre_delete_term' ) && $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $wpdb->terms WHERE term_id = %d;", $id ) ) ) {
129
  // Always keep a group for terms to allow relationships remap when importing from a WXR file
130
  $translations[ $slug ] = $id;
131
  wp_insert_term( $group = uniqid( 'pll_' ), 'term_translations', array( 'description' => serialize( $translations ) ) );
js/post.js CHANGED
@@ -131,9 +131,11 @@
131
  });
132
  }
133
 
134
- var data = wpAjax.unserialize( settings.data ); // what were the data sent by the ajax request?
135
- if ( 'undefined' != typeof( data['action'] ) && 'inline-save' == data['action'] ) {
136
- update_rows( data['post_ID'] );
 
 
137
  }
138
  });
139
  })( jQuery );
131
  });
132
  }
133
 
134
+ if ( 'string' == typeof( settings.data ) ) { // Need to check the type due to Gutenberg sometime sending FormData objects
135
+ var data = wpAjax.unserialize( settings.data ); // what were the data sent by the ajax request?
136
+ if ( 'undefined' != typeof( data['action'] ) && 'inline-save' == data['action'] ) {
137
+ update_rows( data['post_ID'] );
138
+ }
139
  }
140
  });
141
  })( jQuery );
js/post.min.js CHANGED
@@ -1 +1 @@
1
- !function(t){t.ajaxPrefilter(function(a){"string"!=typeof a.data||-1===a.url.indexOf("action=ajax-tag-search")&&-1===a.data.indexOf("action=ajax-tag-search")||!(lang=t(".post_lang_choice").val())&&!(lang=t(':input[name="inline_lang_choice"]').val())||(a.data="lang="+lang+"&"+a.data)})}(jQuery),function(t){tagBox.get=function(a){var n=a.substr(a.indexOf("-")+1),e={action:"get-tagcloud",lang:t(".post_lang_choice").val(),tax:n};t.post(ajaxurl,e,function(e,i){0!=e&&"success"==i||(e=wpAjax.broken),e=t('<div id="tagcloud-'+n+'" class="the-tagcloud">'+e+"</div>"),t("a",e).click(function(){return tagBox.flushTags(t(this).closest(".inside").children(".tagsdiv"),this),!1}),(v=t(".the-tagcloud").css("display"))?(t(".the-tagcloud").replaceWith(e),t(".the-tagcloud").css("display",v)):t("#"+a).after(e)})}}(jQuery),function(t){t(document).bind("DOMNodeInserted",function(a){function n(a){"undefined"!=typeof pll_term_languages&&t.each(pll_term_languages,function(n,e){t.each(e,function(e,i){t.each(i,function(i){id="#"+e+"-"+pll_term_languages[n][e][i],a==n?t(id).show():t(id).hide()})})})}function e(a){"undefined"!=typeof pll_page_languages&&t.each(pll_page_languages,function(n,e){t.each(e,function(e){v=t('#post_parent option[value="'+pll_page_languages[n][e]+'"]'),a==n?v.show():v.hide()})})}var i=t(a.target);if("inline-edit"==i.attr("id")){var l=i.prev().attr("id").replace("post-","");if(l>0){var s=i.find(':input[name="inline_lang_choice"]'),o=t("#lang_"+l).html();s.val(o),n(o),e(o),s.change(function(){n(t(this).val()),e(t(this).val())})}}})}(jQuery),function(t){t(document).ajaxSuccess(function(a,n,e){function i(a){var n=new Array;t(".translation_"+a).each(function(){n.push(t(this).parent().parent().attr("id").substring(5))});var e={action:"pll_update_post_rows",post_id:a,translations:n.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(a){if(a){var n=wpAjax.parseAjaxResponse(a,"ajax-response");t.each(n.responses,function(){"row"==this.what&&t("#post-"+this.supplemental.post_id).replaceWith(this.data)})}})}var l=wpAjax.unserialize(e.data);"undefined"!=typeof l.action&&"inline-save"==l.action&&i(l.post_ID)})}(jQuery),jQuery(document).ready(function(t){function a(){t(".tr_lang").each(function(){var a=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="+a+"&post_type="+t("#post_type").val()+"&_pll_nonce="+t("#_pll_nonce").val(),select:function(e,i){t("#htr_lang_"+a).val(i.item.id),n.html(i.item.link)}}),t(this).blur(function(){t(this).val()||(t("#htr_lang_"+a).val(0),n.html(n.siblings(".hidden").children().clone()))})})}var n=new Array;t(".categorydiv").each(function(){var a,e,i=t(this).attr("id");a=i.split("-"),a.shift(),e=a.join("-"),n.push(e),t("#"+e+"-add-submit").before(t("<input />").attr("type","hidden").attr("id",e+"-lang").attr("name","term_lang_choice").attr("value",t(".post_lang_choice").val()))}),t(".post_lang_choice").change(function(){var e=t(this).val(),i=t(this).children('option[value="'+e+'"]').attr("lang"),l=t('.pll-translation-column > span[lang="'+i+'"]').attr("dir"),s={action:"post_lang_choice",lang:e,post_type:t("#post_type").val(),taxonomies:n,post_id:t("#post_ID").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,s,function(n){var e=wpAjax.parseAjaxResponse(n,"ajax-response");t.each(e.responses,function(){switch(this.what){case"translations":t(".translations").html(this.data),a();break;case"taxonomy":var n=this.data;t("#"+n+"checklist").html(this.supplemental.all),t("#"+n+"checklist-pop").html(this.supplemental.populars),t("#new"+n+"_parent").replaceWith(this.supplemental.dropdown),t("#"+n+"-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 e=t("#edit-slug-box");"-1"!=this.data&&e.children().length&&e.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-"+l),t("#content_ifr").contents().find("html").attr("lang",i).attr("dir",l),t("#content_ifr").contents().find("body").attr("dir",l)})}),a()});
1
+ !function(t){t.ajaxPrefilter(function(a,n,e){"string"!=typeof a.data||-1===a.url.indexOf("action=ajax-tag-search")&&-1===a.data.indexOf("action=ajax-tag-search")||!(lang=t(".post_lang_choice").val())&&!(lang=t(':input[name="inline_lang_choice"]').val())||(a.data="lang="+lang+"&"+a.data)})}(jQuery),function(t){tagBox.get=function(a){var n=a.substr(a.indexOf("-")+1),e={action:"get-tagcloud",lang:t(".post_lang_choice").val(),tax:n};t.post(ajaxurl,e,function(e,i){(0==e||"success"!=i)&&(e=wpAjax.broken),e=t('<div id="tagcloud-'+n+'" class="the-tagcloud">'+e+"</div>"),t("a",e).click(function(){return tagBox.flushTags(t(this).closest(".inside").children(".tagsdiv"),this),!1}),(v=t(".the-tagcloud").css("display"))?(t(".the-tagcloud").replaceWith(e),t(".the-tagcloud").css("display",v)):t("#"+a).after(e)})}}(jQuery),function(t){t(document).bind("DOMNodeInserted",function(a){function n(a){"undefined"!=typeof pll_term_languages&&t.each(pll_term_languages,function(n,e){t.each(e,function(e,i){t.each(i,function(i){id="#"+e+"-"+pll_term_languages[n][e][i],a==n?t(id).show():t(id).hide()})})})}function e(a){"undefined"!=typeof pll_page_languages&&t.each(pll_page_languages,function(n,e){t.each(e,function(e){v=t('#post_parent option[value="'+pll_page_languages[n][e]+'"]'),a==n?v.show():v.hide()})})}var i=t(a.target);if("inline-edit"==i.attr("id")){var l=i.prev().attr("id").replace("post-","");if(l>0){var s=i.find(':input[name="inline_lang_choice"]'),o=t("#lang_"+l).html();s.val(o),n(o),e(o),s.change(function(){n(t(this).val()),e(t(this).val())})}}})}(jQuery),function(t){t(document).ajaxSuccess(function(a,n,e){function i(a){var n=new Array;t(".translation_"+a).each(function(){n.push(t(this).parent().parent().attr("id").substring(5))});var e={action:"pll_update_post_rows",post_id:a,translations:n.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(a){if(a){var n=wpAjax.parseAjaxResponse(a,"ajax-response");t.each(n.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),jQuery(document).ready(function(t){function a(){t(".tr_lang").each(function(){var a=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="+a+"&post_type="+t("#post_type").val()+"&_pll_nonce="+t("#_pll_nonce").val(),select:function(e,i){t("#htr_lang_"+a).val(i.item.id),n.html(i.item.link)}}),t(this).blur(function(){t(this).val()||(t("#htr_lang_"+a).val(0),n.html(n.siblings(".hidden").children().clone()))})})}var n=new Array;t(".categorydiv").each(function(){var a,e,i=t(this).attr("id");a=i.split("-"),a.shift(),e=a.join("-"),n.push(e),t("#"+e+"-add-submit").before(t("<input />").attr("type","hidden").attr("id",e+"-lang").attr("name","term_lang_choice").attr("value",t(".post_lang_choice").val()))}),t(".post_lang_choice").change(function(){var e=t(this).val(),i=t(this).children('option[value="'+e+'"]').attr("lang"),l=t('.pll-translation-column > span[lang="'+i+'"]').attr("dir"),s={action:"post_lang_choice",lang:e,post_type:t("#post_type").val(),taxonomies:n,post_id:t("#post_ID").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,s,function(n){var e=wpAjax.parseAjaxResponse(n,"ajax-response");t.each(e.responses,function(){switch(this.what){case"translations":t(".translations").html(this.data),a();break;case"taxonomy":var n=this.data;t("#"+n+"checklist").html(this.supplemental.all),t("#"+n+"checklist-pop").html(this.supplemental.populars),t("#new"+n+"_parent").replaceWith(this.supplemental.dropdown),t("#"+n+"-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 e=t("#edit-slug-box");"-1"!=this.data&&e.children().length&&e.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-"+l),t("#content_ifr").contents().find("html").attr("lang",i).attr("dir",l),t("#content_ifr").contents().find("body").attr("dir",l)})}),a()});
lingotek/lingotek.php CHANGED
@@ -179,6 +179,10 @@ class PLL_Lingotek {
179
  height: 630px;
180
  background: #fafafa;
181
  }
 
 
 
 
182
  .ltk-feature h3 {
183
  height: 1em;
184
  }
@@ -194,10 +198,16 @@ class PLL_Lingotek {
194
  .ltk-feature ul {
195
  margin-left: 10px;
196
  }
 
 
 
197
  .ltk-feature ul li {
198
  list-style: inside disc;
199
  list-style-position: outside;
200
- padding-left: 0;
 
 
 
201
  }
202
  .ltk-feature .ltk-desc {
203
  height: 3em;
@@ -210,8 +220,6 @@ class PLL_Lingotek {
210
  .ltk-feature .ltk-lower {
211
  padding: 5px 20px 0px 20px;
212
  border-top: 1px solid #eee;
213
-
214
- text-align: left;
215
  font-size: 95%;
216
  }
217
 
179
  height: 630px;
180
  background: #fafafa;
181
  }
182
+ .rtl .ltk-feature {
183
+ text-align: right;
184
+ float: right;
185
+ }
186
  .ltk-feature h3 {
187
  height: 1em;
188
  }
198
  .ltk-feature ul {
199
  margin-left: 10px;
200
  }
201
+ .rtl .ltk-feature ul {
202
+ margin-right: 10px;
203
+ }
204
  .ltk-feature ul li {
205
  list-style: inside disc;
206
  list-style-position: outside;
207
+ padding-left: 0;
208
+ }
209
+ .rtl .ltk-feature ul li {
210
+ padding-right: 0;
211
  }
212
  .ltk-feature .ltk-desc {
213
  height: 3em;
220
  .ltk-feature .ltk-lower {
221
  padding: 5px 20px 0px 20px;
222
  border-top: 1px solid #eee;
 
 
223
  font-size: 95%;
224
  }
225
 
modules/plugins/cache-compat.php CHANGED
@@ -33,9 +33,11 @@ class PLL_Cache_Compat {
33
  public function add_cookie_script() {
34
  $domain = ( 2 == PLL()->options['force_lang'] ) ? parse_url( PLL()->links_model->home, PHP_URL_HOST ) : COOKIE_DOMAIN;
35
  $js = sprintf( '
36
- var date = new Date();
37
- date.setTime( date.getTime() + %d );
38
- document.cookie = "%s=%s; expires=" + date.toUTCString() + "; path=%s%s";',
 
 
39
  esc_js( apply_filters( 'pll_cookie_expiration', YEAR_IN_SECONDS ) ),
40
  esc_js( PLL_COOKIE ),
41
  esc_js( pll_current_language() ),
33
  public function add_cookie_script() {
34
  $domain = ( 2 == PLL()->options['force_lang'] ) ? parse_url( PLL()->links_model->home, PHP_URL_HOST ) : COOKIE_DOMAIN;
35
  $js = sprintf( '
36
+ (function() {
37
+ var expirationDate = new Date();
38
+ expirationDate.setTime( expirationDate.getTime() + %d * 1000 );
39
+ document.cookie = "%s=%s; expires=" + expirationDate.toUTCString() + "; path=%s%s";
40
+ }());',
41
  esc_js( apply_filters( 'pll_cookie_expiration', YEAR_IN_SECONDS ) ),
42
  esc_js( PLL_COOKIE ),
43
  esc_js( pll_current_language() ),
modules/plugins/plugins-compat.php CHANGED
@@ -16,6 +16,7 @@ class PLL_Plugins_Compat {
16
  */
17
  protected function __construct() {
18
  add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 0 );
 
19
 
20
  // WordPress Importer
21
  add_action( 'init', array( $this, 'maybe_wordpress_importer' ) );
@@ -82,17 +83,10 @@ class PLL_Plugins_Compat {
82
  add_action( 'pll_language_defined', array( $this->wpseo = new PLL_WPSEO(), 'init' ) );
83
  }
84
 
85
- // Cache plugins, with specific test for WP Fastest Cache which doesn't use WP_CACHE
86
- if ( ( defined( 'WP_CACHE' ) && WP_CACHE ) || defined( 'WPFC_MAIN_PATH' ) ) {
87
  add_action( 'pll_init', array( $this->cache_compat = new PLL_Cache_Compat(), 'init' ) );
88
  }
89
 
90
- // Advanced Custom Fields Pro
91
- // The function acf_get_value() is not defined in ACF 4
92
- if ( class_exists( 'acf' ) && function_exists( 'acf_get_value' ) && class_exists( 'PLL_ACF' ) ) {
93
- add_action( 'init', array( $this->acf = new PLL_ACF(), 'init' ) );
94
- }
95
-
96
  // Custom Post Type UI
97
  if ( defined( 'CPTUI_VERSION' ) && class_exists( 'PLL_CPTUI' ) ) {
98
  add_action( 'pll_init', array( $this->cptui = new PLL_CPTUI(), 'init' ) );
@@ -114,6 +108,19 @@ class PLL_Plugins_Compat {
114
  }
115
  }
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  /**
118
  * WordPress Importer
119
  * If WordPress Importer is active, replace the wordpress_importer_init function
16
  */
17
  protected function __construct() {
18
  add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 0 );
19
+ add_action( 'after_setup_theme', array( $this, 'after_setup_theme' ) );
20
 
21
  // WordPress Importer
22
  add_action( 'init', array( $this, 'maybe_wordpress_importer' ) );
83
  add_action( 'pll_language_defined', array( $this->wpseo = new PLL_WPSEO(), 'init' ) );
84
  }
85
 
86
+ if ( pll_is_cache_active() ) {
 
87
  add_action( 'pll_init', array( $this->cache_compat = new PLL_Cache_Compat(), 'init' ) );
88
  }
89
 
 
 
 
 
 
 
90
  // Custom Post Type UI
91
  if ( defined( 'CPTUI_VERSION' ) && class_exists( 'PLL_CPTUI' ) ) {
92
  add_action( 'pll_init', array( $this->cptui = new PLL_CPTUI(), 'init' ) );
108
  }
109
  }
110
 
111
+ /**
112
+ * Look for active plugins and load compatibility layer after the theme has been setup
113
+ *
114
+ * @since 2.3.8
115
+ */
116
+ public function after_setup_theme() {
117
+ // Advanced Custom Fields Pro
118
+ // The function acf_get_value() is not defined in ACF 4
119
+ if ( class_exists( 'acf' ) && function_exists( 'acf_get_value' ) && class_exists( 'PLL_ACF' ) ) {
120
+ add_action( 'init', array( $this->acf = new PLL_ACF(), 'init' ) );
121
+ }
122
+ }
123
+
124
  /**
125
  * WordPress Importer
126
  * If WordPress Importer is active, replace the wordpress_importer_init function
modules/sync/admin-sync.php CHANGED
@@ -29,6 +29,8 @@ class PLL_Admin_Sync {
29
  add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
30
  add_action( 'pll_save_term', array( $this, 'sync_term_parent' ), 10, 3 );
31
 
 
 
32
  if ( $this->options['media_support'] ) {
33
  add_action( 'pll_translate_media', array( $this->taxonomies, 'copy' ), 10, 3 );
34
  add_action( 'pll_translate_media', array( $this->post_metas, 'copy' ), 10, 3 );
29
  add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
30
  add_action( 'pll_save_term', array( $this, 'sync_term_parent' ), 10, 3 );
31
 
32
+ add_action( 'pll_duplicate_term', array( $this->term_metas, 'copy' ), 10, 3 );
33
+
34
  if ( $this->options['media_support'] ) {
35
  add_action( 'pll_translate_media', array( $this->taxonomies, 'copy' ), 10, 3 );
36
  add_action( 'pll_translate_media', array( $this->post_metas, 'copy' ), 10, 3 );
modules/wpml/wpml-legacy-api.php CHANGED
@@ -63,8 +63,8 @@ if ( ! function_exists( 'icl_get_languages' ) ) {
63
  }
64
 
65
  foreach ( $languages as $lang ) {
66
- // We can find a translation only on frontend
67
- if ( method_exists( PLL()->links, 'get_translation_url' ) ) {
68
  $url = PLL()->links->get_translation_url( $lang );
69
  }
70
 
63
  }
64
 
65
  foreach ( $languages as $lang ) {
66
+ // We can find a translation only on frontend once the global $wp_query object has been instantiated
67
+ if ( method_exists( PLL()->links, 'get_translation_url' ) && ! empty( $GLOBALS['wp_query'] ) ) {
68
  $url = PLL()->links->get_translation_url( $lang );
69
  }
70
 
polylang.php CHANGED
@@ -3,7 +3,7 @@
3
  /**
4
  Plugin Name: Polylang
5
  Plugin URI: https://polylang.pro
6
- Version: 2.3.7
7
  Author: Frédéric Demarle
8
  Author uri: https://polylang.pro
9
  Description: Adds multilingual capability to WordPress
@@ -53,7 +53,7 @@ if ( defined( 'POLYLANG_BASENAME' ) ) {
53
  }
54
  } else {
55
  // Go on loading the plugin
56
- define( 'POLYLANG_VERSION', '2.3.7' );
57
  define( 'PLL_MIN_WP_VERSION', '4.4' );
58
 
59
  define( 'POLYLANG_FILE', __FILE__ ); // this file
3
  /**
4
  Plugin Name: Polylang
5
  Plugin URI: https://polylang.pro
6
+ Version: 2.3.8
7
  Author: Frédéric Demarle
8
  Author uri: https://polylang.pro
9
  Description: Adds multilingual capability to WordPress
53
  }
54
  } else {
55
  // Go on loading the plugin
56
+ define( 'POLYLANG_VERSION', '2.3.8' );
57
  define( 'PLL_MIN_WP_VERSION', '4.4' );
58
 
59
  define( 'POLYLANG_FILE', __FILE__ ); // this file
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://polylang.pro
4
  Tags: multilingual, bilingual, translate, translation, language, multilanguage, international, localization
5
  Requires at least: 4.4
6
  Tested up to: 4.9
7
- Stable tag: 2.3.7
8
  License: GPLv2 or later
9
 
10
  Making WordPress multilingual
@@ -76,6 +76,23 @@ Don't hesitate to [give your feedback](http://wordpress.org/support/view/plugin-
76
 
77
  == Changelog ==
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  = 2.3.7 (2018-06-07) =
80
 
81
  * Pro: The Events Calendar: Fix untranslated events shown in all languages
4
  Tags: multilingual, bilingual, translate, translation, language, multilanguage, international, localization
5
  Requires at least: 4.4
6
  Tested up to: 4.9
7
+ Stable tag: 2.3.8
8
  License: GPLv2 or later
9
 
10
  Making WordPress multilingual
76
 
77
  == Changelog ==
78
 
79
+ = 2.3.8 (2018-07-16) =
80
+
81
+ * Pro: Duplicate term meta when duplicating a post creates new terms
82
+ * Pro: Add compatibility with ACF Pro when it's bundled with the theme
83
+ * Pro: Fix a fatal error when duplicating posts
84
+ * Set cookie during the home redirect
85
+ * Accept a port in the url to detect the site home
86
+ * Add filter 'pll_is_cache_active' to allow to load the cache compatibility #270 #274
87
+ * Fix potential fatal error when a 3rd party misuses the 'wpml_active_languages' filter #268
88
+ * Fix Uncaught TypeError: s.split is not a function. Props Wouter Van Vliet #262
89
+ * Fix text alignment for RTL scripts in Lingotek panel #247
90
+ * Fix html language attribute filter on admin
91
+ * Fix cookie expiration time when set in js. Props Jens Nachtigall #271
92
+ * Fix fatal error when a 3rd party misuses the WP_Query tax_query param. Props JanneAalto #252
93
+ * Fix an edge case which could mess home pages on a multisite
94
+
95
+
96
  = 2.3.7 (2018-06-07) =
97
 
98
  * Pro: The Events Calendar: Fix untranslated events shown in all languages
settings/view-tab-lang.php CHANGED
@@ -34,8 +34,8 @@ if ( ! defined( 'ABSPATH' ) ) {
34
  // Adds noheader=true in the action url to allow using wp_redirect when processing the form
35
  ?>
36
  <form id="add-lang" method="post" action="admin.php?page=mlang&amp;noheader=true" class="validate">
37
- <?php
38
- wp_nonce_field( 'add-lang', '_wpnonce_add-lang' );
39
 
40
  if ( ! empty( $edit_lang ) ) {
41
  ?>
@@ -47,127 +47,127 @@ if ( ! defined( 'ABSPATH' ) ) {
47
  <input type="hidden" name="pll_action" value="add" />
48
  <?php
49
  }
50
- ?>
51
- <div class="form-field">
52
- <label for="lang_list"><?php esc_html_e( 'Choose a language', 'polylang' ); ?></label>
53
- <select name="lang_list" id="lang_list">
54
- <option value=""></option>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  <?php
56
- foreach ( $this->get_predefined_languages() as $lg ) {
57
- printf(
58
- '<option value="%1$s:%2$s:%3$s:%4$s">%5$s - %2$s</option>' . "\n",
59
- esc_attr( $lg['code'] ),
60
- esc_attr( $lg['locale'] ),
61
- 'rtl' == $lg['dir'] ? '1' : '0',
62
- esc_attr( $lg['flag'] ),
63
- esc_html( $lg['name'] )
64
- );
65
- }
66
  ?>
67
- </select>
68
- <p><?php esc_html_e( 'You can choose a language in the list or directly edit it below.', 'polylang' ); ?></p>
69
- </div>
70
 
71
- <div class="form-field form-required">
72
- <label for="lang_name"><?php esc_html_e( 'Full name', 'polylang' ); ?></label>
73
- <?php
74
- printf(
75
- '<input name="name" id="lang_name" type="text" value="%s" size="40" aria-required="true" />',
76
- ! empty( $edit_lang ) ? esc_attr( $edit_lang->name ) : ''
77
- );
78
- ?>
79
- <p><?php esc_html_e( 'The name is how it is displayed on your site (for example: English).', 'polylang' ); ?></p>
80
- </div>
81
 
82
- <div class="form-field form-required">
83
- <label for="lang_locale"><?php esc_html_e( 'Locale', 'polylang' ); ?></label>
84
- <?php
85
- printf(
86
- '<input name="locale" id="lang_locale" type="text" value="%s" size="40" aria-required="true" />',
87
- ! empty( $edit_lang ) ? esc_attr( $edit_lang->locale ) : ''
88
- );
89
- ?>
90
- <p><?php esc_html_e( 'WordPress Locale for the language (for example: en_US). You will need to install the .mo file for this language.', 'polylang' ); ?></p>
91
- </div>
92
 
93
- <div class="form-field">
94
- <label for="lang_slug"><?php esc_html_e( 'Language code', 'polylang' ); ?></label>
95
- <?php
96
- printf(
97
- '<input name="slug" id="lang_slug" type="text" value="%s" size="40"/>',
98
- ! empty( $edit_lang ) ? esc_attr( $edit_lang->slug ) : ''
99
- );
100
- ?>
101
- <p><?php esc_html_e( 'Language code - preferably 2-letters ISO 639-1 (for example: en)', 'polylang' ); ?></p>
102
- </div>
 
 
 
 
 
 
103
 
104
- <div class="form-field"><fieldset>
105
- <legend><?php esc_html_e( 'Text direction', 'polylang' ); ?></legend>
106
- <?php
107
- printf(
108
- '<label><input name="rtl" type="radio" value="0" %s /> %s</label>',
109
- ! empty( $edit_lang ) && $edit_lang->is_rtl ? '' : 'checked="checked"',
110
- esc_html__( 'left to right', 'polylang' )
111
- );
112
- printf(
113
- '<label><input name="rtl" type="radio" value="1" %s /> %s</label>',
114
- ! empty( $edit_lang ) && $edit_lang->is_rtl ? 'checked="checked"' : '',
115
- esc_html__( 'right to left', 'polylang' )
116
- );
117
- ?>
118
- <p><?php esc_html_e( 'Choose the text direction for the language', 'polylang' ); ?></p>
119
- </fieldset></div>
 
 
120
 
121
- <div class="form-field">
122
- <label for="flag_list"><?php esc_html_e( 'Flag', 'polylang' ); ?></label>
123
- <select name="flag" id="flag_list">
124
- <option value=""></option>
125
  <?php
126
- include PLL_SETTINGS_INC . '/flags.php';
127
- foreach ( $flags as $code => $label ) {
128
- printf(
129
- '<option value="%1$s"%2$s>%3$s</option>' . "\n",
130
- esc_attr( $code ),
131
- isset( $edit_lang->flag_code ) && $edit_lang->flag_code == $code ? ' selected="selected"' : '',
132
- esc_html( $label )
133
- );
134
- }
135
  ?>
136
- </select>
137
- <p><?php esc_html_e( 'Choose a flag for the language.', 'polylang' ); ?></p>
138
- </div>
139
-
140
- <div class="form-field">
141
- <label for="lang_order"><?php esc_html_e( 'Order', 'polylang' ); ?></label>
142
  <?php
143
- printf(
144
- '<input name="term_group" id="lang_order" type="text" value="%d" />',
145
- ! empty( $edit_lang ) ? esc_attr( $edit_lang->term_group ) : ''
146
- );
147
- ?>
148
- <p><?php esc_html_e( 'Position of the language in the language switcher', 'polylang' ); ?></p>
149
- </div>
150
- <?php
151
- if ( ! empty( $edit_lang ) ) {
152
- /**
153
- * Fires after the Edit Language form fields are displayed.
154
- *
155
- * @since 1.7.10
156
- *
157
- * @param object $lang language being edited.
158
- */
159
- do_action( 'pll_language_edit_form_fields', $edit_lang );
160
- } else {
161
- /**
162
- * Fires after the Add Language form fields are displayed.
163
- *
164
- * @since 1.7.10
165
- */
166
- do_action( 'pll_language_add_form_fields' );
167
- }
168
 
169
- submit_button( ! empty( $edit_lang ) ? __( 'Update' ) : __( 'Add new language', 'polylang' ) ); // since WP 3.1
170
- ?>
171
  </form>
172
  </div><!-- form-wrap -->
173
  </div><!-- col-wrap -->
34
  // Adds noheader=true in the action url to allow using wp_redirect when processing the form
35
  ?>
36
  <form id="add-lang" method="post" action="admin.php?page=mlang&amp;noheader=true" class="validate">
37
+ <?php
38
+ wp_nonce_field( 'add-lang', '_wpnonce_add-lang' );
39
 
40
  if ( ! empty( $edit_lang ) ) {
41
  ?>
47
  <input type="hidden" name="pll_action" value="add" />
48
  <?php
49
  }
50
+ ?>
51
+ <div class="form-field">
52
+ <label for="lang_list"><?php esc_html_e( 'Choose a language', 'polylang' ); ?></label>
53
+ <select name="lang_list" id="lang_list">
54
+ <option value=""></option>
55
+ <?php
56
+ foreach ( $this->get_predefined_languages() as $lg ) {
57
+ printf(
58
+ '<option value="%1$s:%2$s:%3$s:%4$s">%5$s - %2$s</option>' . "\n",
59
+ esc_attr( $lg['code'] ),
60
+ esc_attr( $lg['locale'] ),
61
+ 'rtl' == $lg['dir'] ? '1' : '0',
62
+ esc_attr( $lg['flag'] ),
63
+ esc_html( $lg['name'] )
64
+ );
65
+ }
66
+ ?>
67
+ </select>
68
+ <p><?php esc_html_e( 'You can choose a language in the list or directly edit it below.', 'polylang' ); ?></p>
69
+ </div>
70
+
71
+ <div class="form-field form-required">
72
+ <label for="lang_name"><?php esc_html_e( 'Full name', 'polylang' ); ?></label>
73
  <?php
74
+ printf(
75
+ '<input name="name" id="lang_name" type="text" value="%s" size="40" aria-required="true" />',
76
+ ! empty( $edit_lang ) ? esc_attr( $edit_lang->name ) : ''
77
+ );
 
 
 
 
 
 
78
  ?>
79
+ <p><?php esc_html_e( 'The name is how it is displayed on your site (for example: English).', 'polylang' ); ?></p>
80
+ </div>
 
81
 
82
+ <div class="form-field form-required">
83
+ <label for="lang_locale"><?php esc_html_e( 'Locale', 'polylang' ); ?></label>
84
+ <?php
85
+ printf(
86
+ '<input name="locale" id="lang_locale" type="text" value="%s" size="40" aria-required="true" />',
87
+ ! empty( $edit_lang ) ? esc_attr( $edit_lang->locale ) : ''
88
+ );
89
+ ?>
90
+ <p><?php esc_html_e( 'WordPress Locale for the language (for example: en_US). You will need to install the .mo file for this language.', 'polylang' ); ?></p>
91
+ </div>
92
 
93
+ <div class="form-field">
94
+ <label for="lang_slug"><?php esc_html_e( 'Language code', 'polylang' ); ?></label>
95
+ <?php
96
+ printf(
97
+ '<input name="slug" id="lang_slug" type="text" value="%s" size="40"/>',
98
+ ! empty( $edit_lang ) ? esc_attr( $edit_lang->slug ) : ''
99
+ );
100
+ ?>
101
+ <p><?php esc_html_e( 'Language code - preferably 2-letters ISO 639-1 (for example: en)', 'polylang' ); ?></p>
102
+ </div>
103
 
104
+ <div class="form-field"><fieldset>
105
+ <legend><?php esc_html_e( 'Text direction', 'polylang' ); ?></legend>
106
+ <?php
107
+ printf(
108
+ '<label><input name="rtl" type="radio" value="0" %s /> %s</label>',
109
+ ! empty( $edit_lang ) && $edit_lang->is_rtl ? '' : 'checked="checked"',
110
+ esc_html__( 'left to right', 'polylang' )
111
+ );
112
+ printf(
113
+ '<label><input name="rtl" type="radio" value="1" %s /> %s</label>',
114
+ ! empty( $edit_lang ) && $edit_lang->is_rtl ? 'checked="checked"' : '',
115
+ esc_html__( 'right to left', 'polylang' )
116
+ );
117
+ ?>
118
+ <p><?php esc_html_e( 'Choose the text direction for the language', 'polylang' ); ?></p>
119
+ </fieldset></div>
120
 
121
+ <div class="form-field">
122
+ <label for="flag_list"><?php esc_html_e( 'Flag', 'polylang' ); ?></label>
123
+ <select name="flag" id="flag_list">
124
+ <option value=""></option>
125
+ <?php
126
+ include PLL_SETTINGS_INC . '/flags.php';
127
+ foreach ( $flags as $code => $label ) {
128
+ printf(
129
+ '<option value="%1$s"%2$s>%3$s</option>' . "\n",
130
+ esc_attr( $code ),
131
+ isset( $edit_lang->flag_code ) && $edit_lang->flag_code == $code ? ' selected="selected"' : '',
132
+ esc_html( $label )
133
+ );
134
+ }
135
+ ?>
136
+ </select>
137
+ <p><?php esc_html_e( 'Choose a flag for the language.', 'polylang' ); ?></p>
138
+ </div>
139
 
140
+ <div class="form-field">
141
+ <label for="lang_order"><?php esc_html_e( 'Order', 'polylang' ); ?></label>
 
 
142
  <?php
143
+ printf(
144
+ '<input name="term_group" id="lang_order" type="text" value="%d" />',
145
+ ! empty( $edit_lang ) ? esc_attr( $edit_lang->term_group ) : ''
146
+ );
 
 
 
 
 
147
  ?>
148
+ <p><?php esc_html_e( 'Position of the language in the language switcher', 'polylang' ); ?></p>
149
+ </div>
 
 
 
 
150
  <?php
151
+ if ( ! empty( $edit_lang ) ) {
152
+ /**
153
+ * Fires after the Edit Language form fields are displayed.
154
+ *
155
+ * @since 1.7.10
156
+ *
157
+ * @param object $lang language being edited.
158
+ */
159
+ do_action( 'pll_language_edit_form_fields', $edit_lang );
160
+ } else {
161
+ /**
162
+ * Fires after the Add Language form fields are displayed.
163
+ *
164
+ * @since 1.7.10
165
+ */
166
+ do_action( 'pll_language_add_form_fields' );
167
+ }
 
 
 
 
 
 
 
 
168
 
169
+ submit_button( ! empty( $edit_lang ) ? __( 'Update' ) : __( 'Add new language', 'polylang' ) ); // since WP 3.1
170
+ ?>
171
  </form>
172
  </div><!-- form-wrap -->
173
  </div><!-- col-wrap -->