Polylang - Version 2.2

Version Description

(2017-08-16) =

  • Pro: Add support for the REST API
  • Pro: Add integration with The Events Calendar
  • Pro: Refactor ACF Pro integration for post metas and integrate term metas
  • Pro: Ask confirmation if synchronizing a post overwrites an existing translation
  • Pro: Separate sync post logic from interface
  • Pro: Fix 'Detect browser language' option automatically deactivated
  • Pro: Fix redirect to 404 when the 'page' slug translation includes non alphanumeric characters.
  • Pro: Fix untranslated post type archive slug
  • Pro: Fix ACF taxonomy fields not copied when the taxonomy is not translated #156
  • Pro: Fix fatal error with ACF4
  • Support a different content text direction in admin #45
  • Add support for wildcards and 'copy-once' attribute in wpml-config.xml
  • Add minimal support for the filters 'wpml_display_language_names' and 'icl_ls_languages'
  • Improve compatibility with the plugin WordPress MU Domain Mapping #116
  • Improve speed of the sticky posts filter #41
  • Remove redirect_lang option for multiple domains and subdomains
  • Use secure cookie when using SSL
  • Allow to copy/sync term metas with the filter 'pll_copy_term_metas'
  • Filter ajax requests in term.php according to the term language
  • Add error message in customizer when setting an untranslated static front page #47
  • Load static page class only if we are using a static front page
  • Refactor parse_query filters to use the same code on frontend and admin
  • Don't use add_language_to_link in filters
  • Move ajaxPrefilter footer script on top
  • Use wp_doing_ajax() instead of DOING_AJAX constant
  • Fix queries custom tax not excluded from language filter on admin
  • Fix WP translation not loaded when the language is set from the content on multisite.
  • Fix the list of core post types in PLL_OLT_Manager for WP 4.7+
  • Fix post name and tag slug incorrectly sanitized for German and Danish
  • Fix lang attribute in dropdowns
  • Fix wpml_permalink filter #139
  • Fix WPML constants undefined on backend #151
  • Fix a conflict with the plugin Custom Permalinks #143
  • Fix menu location unexpectedly unset
Download this release

Release Info

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

Code changes from version 2.1.6 to 2.2

Files changed (89) hide show
  1. admin/admin-base.php +31 -17
  2. admin/admin-filters-columns.php +19 -19
  3. admin/admin-filters-post-base.php +1 -1
  4. admin/admin-filters-post.php +33 -70
  5. admin/admin-filters-term.php +15 -13
  6. admin/admin-filters.php +44 -20
  7. admin/admin-links.php +1 -1
  8. admin/admin-model.php +17 -15
  9. admin/admin-nav-menu.php +59 -52
  10. admin/admin-static-pages.php +54 -20
  11. admin/admin-strings.php +4 -4
  12. admin/admin.php +2 -4
  13. admin/view-translations-media.php +18 -13
  14. admin/view-translations-post.php +21 -12
  15. admin/view-translations-term.php +49 -29
  16. changelog.txt +2 -2
  17. css/admin.css +15 -0
  18. css/admin.min.css +1 -1
  19. frontend/choose-lang-content.php +3 -3
  20. frontend/choose-lang-domain.php +1 -1
  21. frontend/choose-lang.php +12 -15
  22. frontend/frontend-filters-links.php +7 -24
  23. frontend/frontend-filters-search.php +1 -1
  24. frontend/frontend-filters.php +22 -8
  25. frontend/frontend-links.php +2 -2
  26. frontend/frontend-nav-menu.php +10 -6
  27. frontend/frontend.php +22 -38
  28. include/api.php +14 -14
  29. include/base.php +2 -0
  30. include/cache.php +9 -7
  31. include/class-polylang.php +43 -32
  32. include/filters-links.php +5 -5
  33. include/filters.php +8 -6
  34. include/functions-wpcom-vip.php +0 -29
  35. include/functions.php +84 -0
  36. include/language.php +4 -4
  37. include/license.php +1 -1
  38. include/links-abstract-domain.php +12 -0
  39. include/links-default.php +1 -1
  40. include/links-directory.php +5 -5
  41. include/links-domain.php +2 -2
  42. include/links-model.php +1 -1
  43. include/links-subdomain.php +2 -2
  44. include/model.php +8 -33
  45. include/olt-manager.php +6 -8
  46. include/pointer.php +12 -12
  47. include/query.php +159 -0
  48. include/static-pages.php +1 -1
  49. include/translated-post.php +1 -0
  50. include/translated-term.php +8 -8
  51. include/walker-dropdown.php +21 -12
  52. include/walker-list.php +13 -4
  53. include/widget-languages.php +5 -3
  54. install/install-base.php +24 -17
  55. install/install.php +14 -12
  56. install/upgrade.php +12 -2
  57. js/admin.js +1 -0
  58. js/admin.min.js +1 -1
  59. js/post.js +11 -2
  60. js/post.min.js +1 -1
  61. js/term.js +9 -2
  62. js/term.min.js +1 -1
  63. lingotek/lingotek.php +21 -14
  64. modules/plugins/plugins-compat.php +75 -16
  65. modules/plugins/wp-import.php +2 -2
  66. modules/share-slug/settings-share-slug.php +3 -2
  67. modules/sync/admin-sync.php +57 -10
  68. modules/sync/settings-sync.php +8 -4
  69. modules/wpml/wpml-api.php +75 -17
  70. modules/wpml/wpml-compat.php +1 -0
  71. modules/wpml/wpml-config.php +61 -14
  72. modules/wpml/wpml-legacy-api.php +150 -146
  73. polylang.php +4 -4
  74. readme.txt +38 -1
  75. settings/settings-browser.php +3 -2
  76. settings/settings-cpt.php +23 -16
  77. settings/settings-licenses.php +18 -15
  78. settings/settings-module.php +29 -30
  79. settings/settings-url.php +88 -51
  80. settings/settings.php +13 -13
  81. settings/table-languages.php +8 -8
  82. settings/table-settings.php +2 -2
  83. settings/table-string.php +5 -5
  84. settings/view-about.php +26 -21
  85. settings/view-languages.php +6 -6
  86. settings/view-tab-lang.php +69 -45
  87. settings/view-tab-settings.php +4 -2
  88. settings/view-tab-strings.php +10 -6
  89. uninstall.php +5 -6
admin/admin-base.php CHANGED
@@ -20,14 +20,14 @@ class PLL_Admin_Base extends PLL_Base {
20
  parent::__construct( $links_model );
21
 
22
  // Plugin i18n, only needed for backend
23
- load_plugin_textdomain( 'polylang', false, basename( POLYLANG_DIR ).'/languages' );
24
 
25
  // Adds the link to the languages panel in the WordPress admin menu
26
  add_action( 'admin_menu', array( $this, 'add_menus' ) );
27
 
28
  // Setup js scripts and css styles
29
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
30
- add_action( 'admin_print_footer_scripts', array( $this, 'admin_print_footer_scripts' ) );
31
 
32
  // Lingotek
33
  if ( ! defined( 'PLL_LINGOTEK_AD' ) || PLL_LINGOTEK_AD ) {
@@ -40,8 +40,6 @@ class PLL_Admin_Base extends PLL_Base {
40
  * Loads the settings pages or the filters base on the request
41
  *
42
  * @since 1.2
43
- *
44
- * @param object $links_model
45
  */
46
  public function init() {
47
  if ( ! $this->model->get_languages_list() ) {
@@ -117,10 +115,10 @@ class PLL_Admin_Base extends PLL_Base {
117
  // 3 => 1 if loaded in footer
118
  // FIXME: check if I can load more scripts in footer
119
  $scripts = array(
120
- 'post' => array( array( 'post', 'media', 'async-upload', 'edit' ), array( 'jquery', 'wp-ajax-response', 'post', 'jquery-ui-autocomplete' ), 0 , 1 ),
121
- 'media' => array( array( 'upload' ), array( 'jquery' ), 0 , 1 ),
122
  'term' => array( array( 'edit-tags', 'term' ), array( 'jquery', 'wp-ajax-response', 'jquery-ui-autocomplete' ), 0, 1 ),
123
- 'user' => array( array( 'profile', 'user-edit' ), array( 'jquery' ), 0 , 0 ),
124
  );
125
 
126
  foreach ( $scripts as $script => $v ) {
@@ -147,13 +145,17 @@ class PLL_Admin_Base extends PLL_Base {
147
  * @since 1.4
148
  */
149
  public function admin_print_footer_scripts() {
150
- global $post_ID;
151
 
152
  $params = array( 'pll_ajax_backend' => 1 );
153
  if ( ! empty( $post_ID ) ) {
154
  $params = array_merge( $params, array( 'pll_post_id' => (int) $post_ID ) );
155
  }
156
 
 
 
 
 
157
  $str = http_build_query( $params );
158
  $arr = json_encode( $params );
159
  ?>
@@ -163,30 +165,31 @@ class PLL_Admin_Base extends PLL_Base {
163
  $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
164
  if ( -1 != options.url.indexOf( ajaxurl ) || -1 != ajaxurl.indexOf( options.url ) ) {
165
  if ( 'undefined' === typeof options.data ) {
166
- options.data = ( 'get' === options.type.toLowerCase() ) ? '<?php echo $str;?>' : <?php echo $arr;?>;
167
  } else {
168
  if ( 'string' === typeof options.data ) {
169
  if ( '' === options.data && 'get' === options.type.toLowerCase() ) {
170
- options.url = options.url+'&<?php echo $str;?>';
171
  } else {
172
  try {
173
  o = $.parseJSON(options.data);
174
- o = $.extend(o, <?php echo $arr;?>);
175
  options.data = JSON.stringify(o);
176
  }
177
  catch(e) {
178
- options.data = '<?php echo $str;?>&'+options.data;
179
  }
180
  }
181
  } else {
182
- options.data = $.extend(options.data, <?php echo $arr;?>);
183
  }
184
  }
185
  }
186
  });
187
  })(jQuery)
188
  }
189
- </script><?php
 
190
  }
191
 
192
  /**
@@ -197,6 +200,15 @@ class PLL_Admin_Base extends PLL_Base {
197
  public function set_current_language() {
198
  $this->curlang = $this->filter_lang;
199
 
 
 
 
 
 
 
 
 
 
200
  // Edit Post
201
  if ( isset( $_REQUEST['pll_post_id'] ) && $lang = $this->model->post->get_language( (int) $_REQUEST['pll_post_id'] ) ) {
202
  $this->curlang = $lang;
@@ -210,6 +222,8 @@ class PLL_Admin_Base extends PLL_Base {
210
  // FIXME 'edit-tags.php' for backward compatibility with WP < 4.5
211
  elseif ( in_array( $GLOBALS['pagenow'], array( 'edit-tags.php', 'term.php' ) ) && isset( $_GET['tag_ID'] ) && $lang = $this->model->term->get_language( (int) $_GET['tag_ID'] ) ) {
212
  $this->curlang = $lang;
 
 
213
  } elseif ( 'edit-tags.php' === $GLOBALS['pagenow'] && isset( $_GET['taxonomy'] ) && $this->model->is_translated_taxonomy( $_GET['taxonomy'] ) ) {
214
  if ( ! empty( $_GET['new_lang'] ) ) {
215
  $this->curlang = $this->model->get_language( $_GET['new_lang'] );
@@ -219,7 +233,7 @@ class PLL_Admin_Base extends PLL_Base {
219
  }
220
 
221
  // Ajax
222
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX && ! empty( $_REQUEST['lang'] ) ) {
223
  $this->curlang = $this->model->get_language( $_REQUEST['lang'] );
224
  }
225
  }
@@ -238,7 +252,7 @@ class PLL_Admin_Base extends PLL_Base {
238
 
239
  // Language for admin language filter: may be empty
240
  // $_GET['lang'] is numeric when editing a language, not when selecting a new language in the filter
241
- if ( ! defined( 'DOING_AJAX' ) && ! empty( $_GET['lang'] ) && ! is_numeric( $_GET['lang'] ) && current_user_can( 'edit_user', $user_id = get_current_user_id() ) ) {
242
  update_user_meta( $user_id, 'pll_filter_content', ( $lang = $this->model->get_language( $_GET['lang'] ) ) ? $lang->slug : '' );
243
  }
244
 
@@ -336,7 +350,7 @@ class PLL_Admin_Base extends PLL_Base {
336
  'id' => 'languages',
337
  'title' => $selected->flag . $title,
338
  'href' => esc_url( add_query_arg( 'lang', $selected->slug, remove_query_arg( 'paged', $url ) ) ),
339
- 'meta' => array( 'title' => __( 'Filters content by language', 'polylang' ) ),
340
  ) );
341
 
342
  foreach ( array_merge( array( $all_item ), $this->model->get_languages_list() ) as $lang ) {
20
  parent::__construct( $links_model );
21
 
22
  // Plugin i18n, only needed for backend
23
+ load_plugin_textdomain( 'polylang', false, basename( POLYLANG_DIR ) . '/languages' );
24
 
25
  // Adds the link to the languages panel in the WordPress admin menu
26
  add_action( 'admin_menu', array( $this, 'add_menus' ) );
27
 
28
  // Setup js scripts and css styles
29
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
30
+ add_action( 'admin_print_footer_scripts', array( $this, 'admin_print_footer_scripts' ), 0 ); // High priority in case an ajax request is sent by an immediately invoked function
31
 
32
  // Lingotek
33
  if ( ! defined( 'PLL_LINGOTEK_AD' ) || PLL_LINGOTEK_AD ) {
40
  * Loads the settings pages or the filters base on the request
41
  *
42
  * @since 1.2
 
 
43
  */
44
  public function init() {
45
  if ( ! $this->model->get_languages_list() ) {
115
  // 3 => 1 if loaded in footer
116
  // FIXME: check if I can load more scripts in footer
117
  $scripts = array(
118
+ 'post' => array( array( 'post', 'media', 'async-upload', 'edit' ), array( 'jquery', 'wp-ajax-response', 'post', 'jquery-ui-autocomplete' ), 0, 1 ),
119
+ 'media' => array( array( 'upload' ), array( 'jquery' ), 0, 1 ),
120
  'term' => array( array( 'edit-tags', 'term' ), array( 'jquery', 'wp-ajax-response', 'jquery-ui-autocomplete' ), 0, 1 ),
121
+ 'user' => array( array( 'profile', 'user-edit' ), array( 'jquery' ), 0, 0 ),
122
  );
123
 
124
  foreach ( $scripts as $script => $v ) {
145
  * @since 1.4
146
  */
147
  public function admin_print_footer_scripts() {
148
+ global $post_ID, $tag_ID;
149
 
150
  $params = array( 'pll_ajax_backend' => 1 );
151
  if ( ! empty( $post_ID ) ) {
152
  $params = array_merge( $params, array( 'pll_post_id' => (int) $post_ID ) );
153
  }
154
 
155
+ if ( ! empty( $tag_ID ) ) {
156
+ $params = array_merge( $params, array( 'pll_term_id' => (int) $tag_ID ) );
157
+ }
158
+
159
  $str = http_build_query( $params );
160
  $arr = json_encode( $params );
161
  ?>
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
  /**
200
  public function set_current_language() {
201
  $this->curlang = $this->filter_lang;
202
 
203
+ // POST
204
+ if ( isset( $_POST['post_lang_choice'] ) && $lang = $this->model->get_language( $_POST['post_lang_choice'] ) ) {
205
+ $this->curlang = $lang;
206
+ } elseif ( isset( $_POST['term_lang_choice'] ) && $lang = $this->model->get_language( $_POST['term_lang_choice'] ) ) {
207
+ $this->curlang = $lang;
208
+ } elseif ( isset( $_POST['inline_lang_choice'] ) && $lang = $this->model->get_language( $_POST['inline_lang_choice'] ) ) {
209
+ $this->curlang = $lang;
210
+ }
211
+
212
  // Edit Post
213
  if ( isset( $_REQUEST['pll_post_id'] ) && $lang = $this->model->post->get_language( (int) $_REQUEST['pll_post_id'] ) ) {
214
  $this->curlang = $lang;
222
  // FIXME 'edit-tags.php' for backward compatibility with WP < 4.5
223
  elseif ( in_array( $GLOBALS['pagenow'], array( 'edit-tags.php', 'term.php' ) ) && isset( $_GET['tag_ID'] ) && $lang = $this->model->term->get_language( (int) $_GET['tag_ID'] ) ) {
224
  $this->curlang = $lang;
225
+ } elseif ( isset( $_REQUEST['pll_term_id'] ) && $lang = $this->model->term->get_language( (int) $_REQUEST['pll_term_id'] ) ) {
226
+ $this->curlang = $lang;
227
  } elseif ( 'edit-tags.php' === $GLOBALS['pagenow'] && isset( $_GET['taxonomy'] ) && $this->model->is_translated_taxonomy( $_GET['taxonomy'] ) ) {
228
  if ( ! empty( $_GET['new_lang'] ) ) {
229
  $this->curlang = $this->model->get_language( $_GET['new_lang'] );
233
  }
234
 
235
  // Ajax
236
+ if ( wp_doing_ajax() && ! empty( $_REQUEST['lang'] ) ) {
237
  $this->curlang = $this->model->get_language( $_REQUEST['lang'] );
238
  }
239
  }
252
 
253
  // Language for admin language filter: may be empty
254
  // $_GET['lang'] is numeric when editing a language, not when selecting a new language in the filter
255
+ if ( ! wp_doing_ajax() && ! empty( $_GET['lang'] ) && ! is_numeric( $_GET['lang'] ) && current_user_can( 'edit_user', $user_id = get_current_user_id() ) ) {
256
  update_user_meta( $user_id, 'pll_filter_content', ( $lang = $this->model->get_language( $_GET['lang'] ) ) ? $lang->slug : '' );
257
  }
258
 
350
  'id' => 'languages',
351
  'title' => $selected->flag . $title,
352
  'href' => esc_url( add_query_arg( 'lang', $selected->slug, remove_query_arg( 'paged', $url ) ) ),
353
+ 'meta' => array( 'title' => __( 'Filters content by language', 'polylang' ) ),
354
  ) );
355
 
356
  foreach ( array_merge( array( $all_item ), $this->model->get_languages_list() ) as $lang ) {
admin/admin-filters-columns.php CHANGED
@@ -25,8 +25,8 @@ class PLL_Admin_Filters_Columns {
25
  foreach ( $this->model->get_translated_post_types() as $type ) {
26
  // use the latest filter late as some plugins purely overwrite what's done by others :(
27
  // specific case for media
28
- add_filter( 'manage_'. ( 'attachment' == $type ? 'upload' : 'edit-'. $type ) .'_columns', array( $this, 'add_post_column' ), 100 );
29
- add_action( 'manage_'. ( 'attachment' == $type ? 'media' : $type .'_posts' ) .'_custom_column', array( $this, 'post_column' ), 10, 2 );
30
  }
31
 
32
  // quick edit and bulk edit
@@ -35,8 +35,8 @@ class PLL_Admin_Filters_Columns {
35
 
36
  // adds the language column in the 'Categories' and 'Post Tags' tables
37
  foreach ( $this->model->get_translated_taxonomies() as $tax ) {
38
- add_filter( 'manage_edit-'.$tax.'_columns', array( $this, 'add_term_column' ) );
39
- add_filter( 'manage_'.$tax.'_custom_column', array( $this, 'term_column' ), 10, 3 );
40
  }
41
 
42
  // ajax responses to update list table rows
@@ -49,8 +49,8 @@ class PLL_Admin_Filters_Columns {
49
  *
50
  * @since 0.8.2
51
  *
52
- * @param array $columns list of table columns
53
- * @param string $before the column before which we want to add our languages
54
  * @return array modified list of columns
55
  */
56
  protected function add_column( $columns, $before ) {
@@ -62,7 +62,7 @@ class PLL_Admin_Filters_Columns {
62
  foreach ( $this->model->get_languages_list() as $language ) {
63
  // don't add the column for the filtered language
64
  if ( empty( $this->filter_lang ) || $language->slug != $this->filter_lang->slug ) {
65
- $columns[ 'language_'.$language->slug ] = $language->flag ? $language->flag . '<span class="screen-reader-text">' . esc_html( $language->name ) . '</span>' : esc_html( $language->slug );
66
  }
67
  }
68
 
@@ -104,11 +104,11 @@ class PLL_Admin_Filters_Columns {
104
  *
105
  * @since 0.1
106
  *
107
- * @param string $column column name
108
- * @param int $post_id
109
  */
110
  public function post_column( $column, $post_id ) {
111
- $inline = defined( 'DOING_AJAX' ) && isset( $_REQUEST['action'], $_POST['inline_lang_choice'] ) && 'inline-save' === $_REQUEST['action'];
112
  $lang = $inline ? $this->model->get_language( $_POST['inline_lang_choice'] ) : $this->model->post->get_language( $post_id );
113
 
114
  if ( false === strpos( $column, 'language_' ) || ! $lang ) {
@@ -119,7 +119,7 @@ class PLL_Admin_Filters_Columns {
119
 
120
  // hidden field containing the post language for quick edit
121
  if ( $column == $this->get_first_language_column() ) {
122
- printf( '<div class="hidden" id="lang_%d">%s</div>', esc_attr( $post_id ), esc_html( $lang->slug ) );
123
  }
124
 
125
  $post_type_object = get_post_type_object( get_post_type( $post_id ) );
@@ -147,7 +147,7 @@ class PLL_Admin_Filters_Columns {
147
  '<span class="pll_icon_tick"><span class="screen-reader-text">%s</span></span>',
148
  /* translators: accessibility text, %s is a native language name */
149
  esc_html( sprintf( __( 'This item is in %s', 'polylang' ), $language->name ) )
150
- );
151
  }
152
  }
153
  // link to add a new translation
@@ -209,11 +209,11 @@ class PLL_Admin_Filters_Columns {
209
  * @since 0.1
210
  *
211
  * @param string $out
212
- * @param string $column column name
213
- * @param int term_id
214
  */
215
  public function term_column( $out, $column, $term_id ) {
216
- $inline = defined( 'DOING_AJAX' ) && isset( $_REQUEST['action'], $_POST['inline_lang_choice'] ) && 'inline-save-tax' === $_REQUEST['action'];
217
  if ( false === strpos( $column, 'language_' ) || ! ( $lang = $inline ? $this->model->get_language( $_POST['inline_lang_choice'] ) : $this->model->term->get_language( $term_id ) ) ) {
218
  return $out;
219
  }
@@ -229,11 +229,11 @@ class PLL_Admin_Filters_Columns {
229
  $language = $this->model->get_language( substr( $column, 9 ) );
230
 
231
  if ( $column == $this->get_first_language_column() ) {
232
- $out = sprintf( '<div class="hidden" id="lang_%d">%s</div>', $term_id, esc_html( $lang->slug ) );
233
 
234
  // identify the default categories to disable the language dropdown in js
235
  if ( in_array( get_option( 'default_category' ), $this->model->term->get_translations( $term_id ) ) ) {
236
- $out .= sprintf( '<div class="hidden" id="default_cat_%1$d">%1$d</div>', $term_id );
237
  }
238
  }
239
 
@@ -258,7 +258,7 @@ class PLL_Admin_Filters_Columns {
258
  '<span class="pll_icon_tick"><span class="screen-reader-text">%s</span></span>',
259
  /* translators: accessibility text, %s is a native language name */
260
  esc_html( sprintf( __( 'This item is in %s', 'polylang' ), $language->name ) )
261
- );
262
  }
263
  }
264
 
@@ -312,7 +312,7 @@ class PLL_Admin_Filters_Columns {
312
  public function ajax_update_term_rows() {
313
  global $wp_list_table;
314
 
315
- if ( ! taxonomy_exists( $taxonomy = $_POST['taxonomy'] ) || ! $this->model->is_translated_taxonomy( $taxonomy ) ) {
316
  die( 0 );
317
  }
318
 
25
  foreach ( $this->model->get_translated_post_types() as $type ) {
26
  // use the latest filter late as some plugins purely overwrite what's done by others :(
27
  // specific case for media
28
+ add_filter( 'manage_' . ( 'attachment' == $type ? 'upload' : 'edit-' . $type ) . '_columns', array( $this, 'add_post_column' ), 100 );
29
+ add_action( 'manage_' . ( 'attachment' == $type ? 'media' : $type . '_posts' ) . '_custom_column', array( $this, 'post_column' ), 10, 2 );
30
  }
31
 
32
  // quick edit and bulk edit
35
 
36
  // adds the language column in the 'Categories' and 'Post Tags' tables
37
  foreach ( $this->model->get_translated_taxonomies() as $tax ) {
38
+ add_filter( 'manage_edit-' . $tax . '_columns', array( $this, 'add_term_column' ) );
39
+ add_filter( 'manage_' . $tax . '_custom_column', array( $this, 'term_column' ), 10, 3 );
40
  }
41
 
42
  // ajax responses to update list table rows
49
  *
50
  * @since 0.8.2
51
  *
52
+ * @param array $columns List of table columns
53
+ * @param string $before The column before which we want to add our languages
54
  * @return array modified list of columns
55
  */
56
  protected function add_column( $columns, $before ) {
62
  foreach ( $this->model->get_languages_list() as $language ) {
63
  // don't add the column for the filtered language
64
  if ( empty( $this->filter_lang ) || $language->slug != $this->filter_lang->slug ) {
65
+ $columns[ 'language_' . $language->slug ] = $language->flag ? $language->flag . '<span class="screen-reader-text">' . esc_html( $language->name ) . '</span>' : esc_html( $language->slug );
66
  }
67
  }
68
 
104
  *
105
  * @since 0.1
106
  *
107
+ * @param string $column Column name
108
+ * @param int $post_id
109
  */
110
  public function post_column( $column, $post_id ) {
111
+ $inline = wp_doing_ajax() && isset( $_REQUEST['action'], $_POST['inline_lang_choice'] ) && 'inline-save' === $_REQUEST['action'];
112
  $lang = $inline ? $this->model->get_language( $_POST['inline_lang_choice'] ) : $this->model->post->get_language( $post_id );
113
 
114
  if ( false === strpos( $column, 'language_' ) || ! $lang ) {
119
 
120
  // hidden field containing the post language for quick edit
121
  if ( $column == $this->get_first_language_column() ) {
122
+ printf( '<div class="hidden" id="lang_%d">%s</div>', intval( $post_id ), esc_html( $lang->slug ) );
123
  }
124
 
125
  $post_type_object = get_post_type_object( get_post_type( $post_id ) );
147
  '<span class="pll_icon_tick"><span class="screen-reader-text">%s</span></span>',
148
  /* translators: accessibility text, %s is a native language name */
149
  esc_html( sprintf( __( 'This item is in %s', 'polylang' ), $language->name ) )
150
+ );
151
  }
152
  }
153
  // link to add a new translation
209
  * @since 0.1
210
  *
211
  * @param string $out
212
+ * @param string $column Column name
213
+ * @param int $term_id
214
  */
215
  public function term_column( $out, $column, $term_id ) {
216
+ $inline = wp_doing_ajax() && isset( $_REQUEST['action'], $_POST['inline_lang_choice'] ) && 'inline-save-tax' === $_REQUEST['action'];
217
  if ( false === strpos( $column, 'language_' ) || ! ( $lang = $inline ? $this->model->get_language( $_POST['inline_lang_choice'] ) : $this->model->term->get_language( $term_id ) ) ) {
218
  return $out;
219
  }
229
  $language = $this->model->get_language( substr( $column, 9 ) );
230
 
231
  if ( $column == $this->get_first_language_column() ) {
232
+ $out = sprintf( '<div class="hidden" id="lang_%d">%s</div>', intval( $term_id ), esc_html( $lang->slug ) );
233
 
234
  // identify the default categories to disable the language dropdown in js
235
  if ( in_array( get_option( 'default_category' ), $this->model->term->get_translations( $term_id ) ) ) {
236
+ $out .= sprintf( '<div class="hidden" id="default_cat_%1$d">%1$d</div>', intval( $term_id ) );
237
  }
238
  }
239
 
258
  '<span class="pll_icon_tick"><span class="screen-reader-text">%s</span></span>',
259
  /* translators: accessibility text, %s is a native language name */
260
  esc_html( sprintf( __( 'This item is in %s', 'polylang' ), $language->name ) )
261
+ );
262
  }
263
  }
264
 
312
  public function ajax_update_term_rows() {
313
  global $wp_list_table;
314
 
315
+ if ( ! taxonomy_exists( $taxonomy = $_POST['taxonomy'] ) || ! $this->model->is_translated_taxonomy( $taxonomy ) ) {
316
  die( 0 );
317
  }
318
 
admin/admin-filters-post-base.php CHANGED
@@ -49,7 +49,7 @@ abstract class PLL_Admin_Filters_Post_Base {
49
  *
50
  * @since 1.5
51
  *
52
- * @param int $post_id
53
  * @param array $arr
54
  * @return array
55
  */
49
  *
50
  * @since 1.5
51
  *
52
+ * @param int $post_id
53
  * @param array $arr
54
  * @return array
55
  */
admin/admin-filters-post.php CHANGED
@@ -42,6 +42,9 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
42
 
43
  // Filters the pages by language in the parent dropdown list in the page attributes metabox
44
  add_filter( 'page_attributes_dropdown_pages_args', array( $this, 'page_attributes_dropdown_pages_args' ), 10, 2 );
 
 
 
45
  }
46
 
47
  /**
@@ -105,67 +108,8 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
105
  * @param object $query a WP_Query object
106
  */
107
  public function parse_query( $query ) {
108
- $qvars = &$query->query_vars;
109
-
110
- // Do not filter post types such as nav_menu_item
111
- if ( isset( $qvars['post_type'] ) && ! $this->model->is_translated_post_type( $qvars['post_type'] ) ) {
112
- unset( $qvars['lang'] );
113
- return;
114
- }
115
-
116
- // Do not filter the query if the language is already specified in another way
117
- if ( ! isset( $qvars['lang'] ) ) {
118
- $excludes = array(
119
- 'p',
120
- 'post_parent',
121
- 'attachment',
122
- 'attachment_id',
123
- 'name',
124
- 'pagename',
125
- 'page_id',
126
- 'category_name',
127
- 'tag',
128
- 'cat',
129
- 'tag_id',
130
- 'category__in',
131
- 'category__and',
132
- 'post__in',
133
- 'post_name__in',
134
- 'tag__in',
135
- 'tag__and',
136
- 'tag_slug__in',
137
- 'tag_slug__and',
138
- 'post_parent__in',
139
- );
140
-
141
- foreach ( $excludes as $k ) {
142
- if ( ! empty( $qvars[ $k ] ) ) {
143
- return;
144
- }
145
- }
146
-
147
- $taxonomies = array_intersect( $this->model->get_translated_taxonomies(), get_taxonomies( array( '_builtin' => false ) ) );
148
-
149
- foreach ( $taxonomies as $tax ) {
150
- $tax = get_taxonomy( $tax );
151
- if ( ! empty( $qv[ $tax->query_var ] ) ) {
152
- return;
153
- }
154
- }
155
-
156
- if ( ! empty( $qvars['tax_query'] ) && is_array( $qvars['tax_query'] ) && $this->model->have_translated_taxonomy( $qvars['tax_query'] ) ) {
157
- return;
158
- }
159
-
160
- // Filter queries according to the current language
161
- if ( isset( $qvars['post_type'] ) && ! empty( $this->curlang ) ) {
162
- $qvars['lang'] = $this->curlang->slug;
163
- }
164
- }
165
-
166
- if ( isset( $qvars['lang'] ) && 'all' === $qvars['lang'] ) {
167
- unset( $qvars['lang'] );
168
- }
169
  }
170
 
171
  /**
@@ -174,14 +118,15 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
174
  *
175
  * @since 0.1
176
  *
177
- * @param string $post_type
 
178
  */
179
  public function add_meta_boxes( $post_type, $post ) {
180
  if ( $this->model->is_translated_post_type( $post_type ) ) {
181
  add_meta_box( 'ml_box', __( 'Languages','polylang' ), array( $this, 'post_language' ), $post_type, 'side', 'high' );
182
  }
183
 
184
- if ( ( $page_for_posts = get_option( 'page_for_posts' ) ) && ( $translations = $this->model->post->get_translations( $page_for_posts ) ) && in_array( $post->ID, $translations ) && empty( $post->post_content ) ) {
185
  add_action( 'edit_form_after_title', '_wp_posts_page_notice' );
186
  remove_post_type_support( $post_type, 'editor' );
187
  }
@@ -282,10 +227,10 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
282
  $supplemental['dropdown'] = wp_dropdown_categories( array(
283
  'taxonomy' => $taxonomy->name,
284
  'hide_empty' => 0,
285
- 'name' => 'new'.$taxonomy->name.'_parent',
286
  'orderby' => 'name',
287
  'hierarchical' => 1,
288
- 'show_option_none' => '&mdash; '.$taxonomy->labels->parent_item.' &mdash;',
289
  'echo' => 0,
290
  ) );
291
 
@@ -346,11 +291,13 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
346
  'numberposts' => 20, // Limit to 20 posts
347
  'post_status' => 'any',
348
  'post_type' => $_GET['post_type'],
349
- 'tax_query' => array( array(
350
- 'taxonomy' => 'language',
351
- 'field' => 'term_taxonomy_id', // WP 3.5+
352
- 'terms' => $translation_language->term_taxonomy_id,
353
- ) ),
 
 
354
  );
355
 
356
  /**
@@ -586,4 +533,20 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
586
 
587
  return $dropdown_args;
588
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  }
42
 
43
  // Filters the pages by language in the parent dropdown list in the page attributes metabox
44
  add_filter( 'page_attributes_dropdown_pages_args', array( $this, 'page_attributes_dropdown_pages_args' ), 10, 2 );
45
+
46
+ // Sets the language in Tiny MCE
47
+ add_filter( 'tiny_mce_before_init', array( $this, 'tiny_mce_before_init' ) );
48
  }
49
 
50
  /**
108
  * @param object $query a WP_Query object
109
  */
110
  public function parse_query( $query ) {
111
+ $pll_query = new PLL_Query( $query, $this->model );
112
+ $pll_query->filter_query( $this->curlang );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  }
114
 
115
  /**
118
  *
119
  * @since 0.1
120
  *
121
+ * @param string $post_type Current post type
122
+ * @param object $post Current post
123
  */
124
  public function add_meta_boxes( $post_type, $post ) {
125
  if ( $this->model->is_translated_post_type( $post_type ) ) {
126
  add_meta_box( 'ml_box', __( 'Languages','polylang' ), array( $this, 'post_language' ), $post_type, 'side', 'high' );
127
  }
128
 
129
+ if ( ( $page_for_posts = get_option( 'page_for_posts' ) ) && ( $translations = $this->model->post->get_translations( $page_for_posts ) ) && in_array( $post->ID, $translations ) && empty( $post->post_content ) ) {
130
  add_action( 'edit_form_after_title', '_wp_posts_page_notice' );
131
  remove_post_type_support( $post_type, 'editor' );
132
  }
227
  $supplemental['dropdown'] = wp_dropdown_categories( array(
228
  'taxonomy' => $taxonomy->name,
229
  'hide_empty' => 0,
230
+ 'name' => 'new' . $taxonomy->name . '_parent',
231
  'orderby' => 'name',
232
  'hierarchical' => 1,
233
+ 'show_option_none' => '&mdash; ' . $taxonomy->labels->parent_item . ' &mdash;',
234
  'echo' => 0,
235
  ) );
236
 
291
  'numberposts' => 20, // Limit to 20 posts
292
  'post_status' => 'any',
293
  'post_type' => $_GET['post_type'],
294
+ 'tax_query' => array(
295
+ array(
296
+ 'taxonomy' => 'language',
297
+ 'field' => 'term_taxonomy_id', // WP 3.5+
298
+ 'terms' => $translation_language->term_taxonomy_id,
299
+ ),
300
+ ),
301
  );
302
 
303
  /**
533
 
534
  return $dropdown_args;
535
  }
536
+
537
+ /**
538
+ * Sets the language attribute and text direction for Tiny MCE
539
+ *
540
+ * @since 2.2
541
+ *
542
+ * @param array $mce_init TinyMCE config
543
+ * @return array
544
+ */
545
+ public function tiny_mce_before_init( $mce_init ) {
546
+ if ( ! empty( $this->curlang ) ) {
547
+ $mce_init['wp_lang_attr'] = $this->curlang->get_locale( 'display' );
548
+ $mce_init['directionality'] = $this->curlang->is_rtl ? 'rtl' : 'ltr';
549
+ }
550
+ return $mce_init;
551
+ }
552
  }
admin/admin-filters-term.php CHANGED
@@ -25,13 +25,13 @@ class PLL_Admin_Filters_Term {
25
 
26
  foreach ( $this->model->get_translated_taxonomies() as $tax ) {
27
  // Adds the language field in the 'Categories' and 'Post Tags' panels
28
- add_action( $tax.'_add_form_fields', array( $this, 'add_term_form' ) );
29
 
30
  // Adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
31
- add_action( $tax.'_edit_form_fields', array( $this, 'edit_term_form' ) );
32
 
33
  // Adds action related to languages when deleting categories and post tags
34
- add_action( 'delete_'.$tax, array( $this, 'delete_term' ) );
35
  }
36
 
37
  // Adds actions related to languages when creating or saving categories and post tags
@@ -103,13 +103,15 @@ class PLL_Admin_Filters_Term {
103
  if ( $lang ) {
104
  include PLL_ADMIN_INC . '/view-translations-term.php';
105
  }
106
- echo '</div>'."\n";
107
  }
108
 
109
  /**
110
  * Adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
111
  *
112
  * @since 0.1
 
 
113
  */
114
  public function edit_term_form( $tag ) {
115
  $post_type = isset( $GLOBALS['post_type'] ) ? $GLOBALS['post_type'] : $_REQUEST['post_type'];
@@ -129,11 +131,10 @@ class PLL_Admin_Filters_Term {
129
  // Disable the language dropdown and the translations input fields for default categories to prevent removal
130
  $disabled = in_array( get_option( 'default_category' ), $this->model->term->get_translations( $term_id ) );
131
 
132
- wp_nonce_field( 'pll_language', '_pll_nonce' );
133
-
134
  printf( '
135
  <tr class="form-field">
136
  <th scope="row">
 
137
  <label for="term_lang_choice">%s</label>
138
  </th>
139
  <td id="select-edit-term-language">
@@ -141,6 +142,7 @@ class PLL_Admin_Filters_Term {
141
  <p class="description">%s</p>
142
  </td>
143
  </tr>',
 
144
  esc_html__( 'Language', 'polylang' ),
145
  $dropdown->walk( $this->model->get_languages_list(), array(
146
  'name' => 'term_lang_choice',
@@ -156,7 +158,7 @@ class PLL_Admin_Filters_Term {
156
  if ( $lang ) {
157
  include PLL_ADMIN_INC . '/view-translations-term.php';
158
  }
159
- echo '</tr>'."\n";
160
  }
161
 
162
  /**
@@ -164,7 +166,7 @@ class PLL_Admin_Filters_Term {
164
  *
165
  * @since 0.7
166
  *
167
- * @param string html markup for dropdown list of categories
168
  * @return string modified html
169
  */
170
  public function wp_dropdown_cats( $output ) {
@@ -419,7 +421,7 @@ class PLL_Admin_Filters_Term {
419
  elseif ( isset( $_GET['bulk_edit'], $_GET['inline_lang_choice'] ) ) {
420
  // Bulk edit does not modify the language
421
  if ( -1 == $_GET['inline_lang_choice'] ) {
422
- $slug = $name . '-' . $this->model->post->get_language( $this->post_id )->slug;
423
  } else {
424
  $slug = $name . '-' . $this->model->get_language( $_GET['inline_lang_choice'] )->slug;
425
  }
@@ -486,7 +488,7 @@ class PLL_Admin_Filters_Term {
486
  // Tests copied from edit_tags.php
487
  else {
488
  $tax = get_taxonomy( $taxonomy );
489
- if ( ! is_null( $tax->labels->popular_items ) ) {
490
  $args = array( 'taxonomy' => $taxonomy, 'echo' => false );
491
  if ( current_user_can( $tax->cap->edit_terms ) ) {
492
  $args = array_merge( $args, array( 'link' => 'edit' ) );
@@ -686,9 +688,9 @@ class PLL_Admin_Filters_Term {
686
  *
687
  * @since 1.7
688
  *
689
- * @param int $term_id shared term_id
690
- * @param int $new_term_id
691
- * @param int $term_taxonomy_id
692
  * @param string $taxonomy
693
  */
694
  public function split_shared_term( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
25
 
26
  foreach ( $this->model->get_translated_taxonomies() as $tax ) {
27
  // Adds the language field in the 'Categories' and 'Post Tags' panels
28
+ add_action( $tax . '_add_form_fields', array( $this, 'add_term_form' ) );
29
 
30
  // Adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
31
+ add_action( $tax . '_edit_form_fields', array( $this, 'edit_term_form' ) );
32
 
33
  // Adds action related to languages when deleting categories and post tags
34
+ add_action( 'delete_' . $tax, array( $this, 'delete_term' ) );
35
  }
36
 
37
  // Adds actions related to languages when creating or saving categories and post tags
103
  if ( $lang ) {
104
  include PLL_ADMIN_INC . '/view-translations-term.php';
105
  }
106
+ echo '</div>' . "\n";
107
  }
108
 
109
  /**
110
  * Adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
111
  *
112
  * @since 0.1
113
+ *
114
+ * @param object $tag
115
  */
116
  public function edit_term_form( $tag ) {
117
  $post_type = isset( $GLOBALS['post_type'] ) ? $GLOBALS['post_type'] : $_REQUEST['post_type'];
131
  // Disable the language dropdown and the translations input fields for default categories to prevent removal
132
  $disabled = in_array( get_option( 'default_category' ), $this->model->term->get_translations( $term_id ) );
133
 
 
 
134
  printf( '
135
  <tr class="form-field">
136
  <th scope="row">
137
+ %s
138
  <label for="term_lang_choice">%s</label>
139
  </th>
140
  <td id="select-edit-term-language">
142
  <p class="description">%s</p>
143
  </td>
144
  </tr>',
145
+ wp_nonce_field( 'pll_language', '_pll_nonce', true , false ),
146
  esc_html__( 'Language', 'polylang' ),
147
  $dropdown->walk( $this->model->get_languages_list(), array(
148
  'name' => 'term_lang_choice',
158
  if ( $lang ) {
159
  include PLL_ADMIN_INC . '/view-translations-term.php';
160
  }
161
+ echo '</tr>' . "\n";
162
  }
163
 
164
  /**
166
  *
167
  * @since 0.7
168
  *
169
+ * @param string $output html markup for dropdown list of categories
170
  * @return string modified html
171
  */
172
  public function wp_dropdown_cats( $output ) {
421
  elseif ( isset( $_GET['bulk_edit'], $_GET['inline_lang_choice'] ) ) {
422
  // Bulk edit does not modify the language
423
  if ( -1 == $_GET['inline_lang_choice'] ) {
424
+ $slug = $name . '-' . $this->model->post->get_language( $this->post_id )->slug;
425
  } else {
426
  $slug = $name . '-' . $this->model->get_language( $_GET['inline_lang_choice'] )->slug;
427
  }
488
  // Tests copied from edit_tags.php
489
  else {
490
  $tax = get_taxonomy( $taxonomy );
491
+ if ( ! is_null( $tax->labels->popular_items ) ) {
492
  $args = array( 'taxonomy' => $taxonomy, 'echo' => false );
493
  if ( current_user_can( $tax->cap->edit_terms ) ) {
494
  $args = array_merge( $args, array( 'link' => 'edit' ) );
688
  *
689
  * @since 1.7
690
  *
691
+ * @param int $term_id Shared term_id
692
+ * @param int $new_term_id
693
+ * @param int $term_taxonomy_id
694
  * @param string $taxonomy
695
  */
696
  public function split_shared_term( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
admin/admin-filters.php CHANGED
@@ -40,6 +40,8 @@ class PLL_Admin_Filters extends PLL_Filters {
40
  add_filter( 'sanitize_title', array( $this, 'sanitize_title' ), 10, 3 );
41
  add_filter( 'sanitize_user', array( $this, 'sanitize_user' ), 10, 3 );
42
  }
 
 
43
  }
44
 
45
  /**
@@ -47,25 +49,32 @@ class PLL_Admin_Filters extends PLL_Filters {
47
  *
48
  * @since 0.3
49
  *
50
- * @param object $widget
 
 
51
  */
52
  public function in_widget_form( $widget, $return, $instance ) {
53
- $dropdown = new PLL_Walker_Dropdown();
54
- printf( '<p><label for="%1$s">%2$s %3$s</label></p>',
55
- esc_attr( $widget->id.'_lang_choice' ),
56
- esc_html__( 'The widget is displayed for:', 'polylang' ),
57
- $dropdown->walk(
58
- array_merge(
59
- array( (object) array( 'slug' => 0, 'name' => __( 'All languages', 'polylang' ) ) ),
60
- $this->model->get_languages_list()
61
- ),
62
- array(
63
- 'name' => $widget->id.'_lang_choice',
64
- 'class' => 'tags-input',
65
- 'selected' => empty( $instance['pll_lang'] ) ? '' : $instance['pll_lang'],
 
 
 
 
 
66
  )
67
- )
68
- );
69
  }
70
 
71
  /**
@@ -81,7 +90,7 @@ class PLL_Admin_Filters extends PLL_Filters {
81
  * @return array Widget options
82
  */
83
  public function widget_update_callback( $instance, $new_instance, $old_instance, $widget ) {
84
- if ( ! empty( $_POST[ $key = $widget->id.'_lang_choice' ] ) && in_array( $_POST[ $key ], $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) ) {
85
  $instance['pll_lang'] = $_POST[ $key ];
86
  } else {
87
  unset( $instance['pll_lang'] );
@@ -185,7 +194,7 @@ class PLL_Admin_Filters extends PLL_Filters {
185
  *
186
  * @since 1.6
187
  *
188
- * @param array $locale not used
189
  * @return array list of locales to update
190
  */
191
  function update_check_locales( $locales ) {
@@ -236,9 +245,9 @@ class PLL_Admin_Filters extends PLL_Filters {
236
  *
237
  * @since 2.0
238
  *
239
- * @param string $username Sanitized username.
240
  * @param string $raw_username The username prior to sanitization.
241
- * @param bool $strict Whether to limit the sanitization to specific characters. Default false.
242
  * @return string
243
  */
244
  public function sanitize_user( $username, $raw_username, $strict ) {
@@ -253,4 +262,19 @@ class PLL_Admin_Filters extends PLL_Filters {
253
  }
254
  return $username;
255
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  }
40
  add_filter( 'sanitize_title', array( $this, 'sanitize_title' ), 10, 3 );
41
  add_filter( 'sanitize_user', array( $this, 'sanitize_user' ), 10, 3 );
42
  }
43
+
44
+ add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
45
  }
46
 
47
  /**
49
  *
50
  * @since 0.3
51
  *
52
+ * @param object $widget Widget instance
53
+ * @param null $return Not used
54
+ * @param array $instance Widget settings
55
  */
56
  public function in_widget_form( $widget, $return, $instance ) {
57
+ $screen = get_current_screen();
58
+
59
+ // Test the Widgets screen and the Customizer to avoid displaying the option in page builders
60
+ if ( ( isset( $screen ) && 'widgets' === $screen->base ) || isset( $GLOBALS['wp_customize'] ) ) {
61
+ $dropdown = new PLL_Walker_Dropdown();
62
+ printf( '<p><label for="%1$s">%2$s %3$s</label></p>',
63
+ esc_attr( $widget->id . '_lang_choice' ),
64
+ esc_html__( 'The widget is displayed for:', 'polylang' ),
65
+ $dropdown->walk(
66
+ array_merge(
67
+ array( (object) array( 'slug' => 0, 'name' => __( 'All languages', 'polylang' ) ) ),
68
+ $this->model->get_languages_list()
69
+ ),
70
+ array(
71
+ 'name' => $widget->id . '_lang_choice',
72
+ 'class' => 'tags-input',
73
+ 'selected' => empty( $instance['pll_lang'] ) ? '' : $instance['pll_lang'],
74
+ )
75
  )
76
+ );
77
+ }
78
  }
79
 
80
  /**
90
  * @return array Widget options
91
  */
92
  public function widget_update_callback( $instance, $new_instance, $old_instance, $widget ) {
93
+ if ( ! empty( $_POST[ $key = $widget->id . '_lang_choice' ] ) && in_array( $_POST[ $key ], $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) ) {
94
  $instance['pll_lang'] = $_POST[ $key ];
95
  } else {
96
  unset( $instance['pll_lang'] );
194
  *
195
  * @since 1.6
196
  *
197
+ * @param array $locales Not used
198
  * @return array list of locales to update
199
  */
200
  function update_check_locales( $locales ) {
245
  *
246
  * @since 2.0
247
  *
248
+ * @param string $username Sanitized username.
249
  * @param string $raw_username The username prior to sanitization.
250
+ * @param bool $strict Whether to limit the sanitization to specific characters. Default false.
251
  * @return string
252
  */
253
  public function sanitize_user( $username, $raw_username, $strict ) {
262
  }
263
  return $username;
264
  }
265
+
266
+ /**
267
+ * Adds a text direction dependent class to the body
268
+ *
269
+ * @since 2.2
270
+ *
271
+ * @param string $classes Space-separated list of CSS classes.
272
+ * @return string
273
+ */
274
+ public function admin_body_class( $classes ) {
275
+ if ( ! empty( $this->curlang ) ) {
276
+ $classes .= ' pll-dir-' . ( $this->curlang->is_rtl ? 'rtl' : 'ltr' );
277
+ }
278
+ return $classes;
279
+ }
280
  }
admin/admin-links.php CHANGED
@@ -137,7 +137,7 @@ class PLL_Admin_Links extends PLL_Links {
137
  *
138
  * @since 1.8
139
  *
140
- * @param int $term_id
141
  * @param string $taxonomy
142
  * @param string $post_type
143
  * @param object $language
137
  *
138
  * @since 1.8
139
  *
140
+ * @param int $term_id
141
  * @param string $taxonomy
142
  * @param string $post_type
143
  * @param object $language
admin/admin-model.php CHANGED
@@ -136,7 +136,7 @@ class PLL_Admin_Model extends PLL_Model {
136
  // Delete users options
137
  foreach ( get_users( array( 'fields' => 'ID' ) ) as $user_id ) {
138
  delete_user_meta( $user_id, 'pll_filter_content', $lang->slug );
139
- delete_user_meta( $user_id, 'description_'.$lang->slug );
140
  }
141
 
142
  // Delete the string translations
@@ -363,7 +363,7 @@ class PLL_Admin_Model extends PLL_Model {
363
  }
364
 
365
  // Get all terms with their term_id
366
- $terms = $wpdb->get_results( "SELECT term_id, slug FROM $wpdb->terms WHERE slug IN ( " . implode( ',', $slugs ) . " )" );
367
 
368
  // Prepare terms taxonomy relationship
369
  foreach ( $terms as $term ) {
@@ -415,11 +415,13 @@ class PLL_Admin_Model extends PLL_Model {
415
  'post_type' => $this->get_translated_post_types(),
416
  'post_status' => 'any',
417
  'fields' => 'ids',
418
- 'tax_query' => array( array(
419
- 'taxonomy' => 'language',
420
- 'terms' => $this->get_languages_list( array( 'fields' => 'term_id' ) ),
421
- 'operator' => 'NOT IN',
422
- ) )
 
 
423
  ) );
424
 
425
  $terms = get_terms( $this->get_translated_taxonomies(), array( 'get' => 'all', 'fields' => 'ids' ) );
@@ -477,24 +479,24 @@ class PLL_Admin_Model extends PLL_Model {
477
  if ( ! empty( $dr ) ) {
478
  $wpdb->query( "
479
  DELETE FROM $wpdb->term_relationships
480
- WHERE object_id IN ( " . implode( ',', $dr['id'] ) . " )
481
- AND term_taxonomy_id IN ( " . implode( ',', $dr['tt'] ) . " )
482
- " );
483
  }
484
 
485
  // Delete terms
486
  if ( ! empty( $dt ) ) {
487
- $wpdb->query( "DELETE FROM $wpdb->terms WHERE term_id IN ( " . implode( ',', $dt['t'] ) . " ) " );
488
- $wpdb->query( "DELETE FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ( " . implode( ',', $dt['tt'] ) . " ) " );
489
  }
490
 
491
  // Update terms
492
  if ( ! empty( $ut ) ) {
493
  $wpdb->query( "
494
  UPDATE $wpdb->term_taxonomy
495
- SET description = ( CASE term_id " . implode( ' ', $ut['case'] ) . " END )
496
- WHERE term_id IN ( " . implode( ',', $ut['in'] ) . " )
497
- " );
498
  }
499
 
500
  if ( ! empty( $term_ids ) ) {
136
  // Delete users options
137
  foreach ( get_users( array( 'fields' => 'ID' ) ) as $user_id ) {
138
  delete_user_meta( $user_id, 'pll_filter_content', $lang->slug );
139
+ delete_user_meta( $user_id, 'description_' . $lang->slug );
140
  }
141
 
142
  // Delete the string translations
363
  }
364
 
365
  // Get all terms with their term_id
366
+ $terms = $wpdb->get_results( "SELECT term_id, slug FROM $wpdb->terms WHERE slug IN ( " . implode( ',', $slugs ) . ' )' );
367
 
368
  // Prepare terms taxonomy relationship
369
  foreach ( $terms as $term ) {
415
  'post_type' => $this->get_translated_post_types(),
416
  'post_status' => 'any',
417
  'fields' => 'ids',
418
+ 'tax_query' => array(
419
+ array(
420
+ 'taxonomy' => 'language',
421
+ 'terms' => $this->get_languages_list( array( 'fields' => 'term_id' ) ),
422
+ 'operator' => 'NOT IN',
423
+ ),
424
+ ),
425
  ) );
426
 
427
  $terms = get_terms( $this->get_translated_taxonomies(), array( 'get' => 'all', 'fields' => 'ids' ) );
479
  if ( ! empty( $dr ) ) {
480
  $wpdb->query( "
481
  DELETE FROM $wpdb->term_relationships
482
+ WHERE object_id IN ( " . implode( ',', $dr['id'] ) . ' )
483
+ AND term_taxonomy_id IN ( ' . implode( ',', $dr['tt'] ) . ' )
484
+ ' );
485
  }
486
 
487
  // Delete terms
488
  if ( ! empty( $dt ) ) {
489
+ $wpdb->query( "DELETE FROM $wpdb->terms WHERE term_id IN ( " . implode( ',', $dt['t'] ) . ' )' );
490
+ $wpdb->query( "DELETE FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ( " . implode( ',', $dt['tt'] ) . ' )' );
491
  }
492
 
493
  // Update terms
494
  if ( ! empty( $ut ) ) {
495
  $wpdb->query( "
496
  UPDATE $wpdb->term_taxonomy
497
+ SET description = ( CASE term_id " . implode( ' ', $ut['case'] ) . ' END )
498
+ WHERE term_id IN ( ' . implode( ',', $ut['in'] ) . ' )
499
+ ' );
500
  }
501
 
502
  if ( ! empty( $term_ids ) ) {
admin/admin-nav-menu.php CHANGED
@@ -1,14 +1,14 @@
1
  <?php
2
 
3
  /**
4
- * manages custom menus translations as well as the language switcher menu item on admin side
5
  *
6
  * @since 1.2
7
  */
8
  class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
9
 
10
  /**
11
- * constructor: setups filters and actions
12
  *
13
  * @since 1.2
14
  *
@@ -19,16 +19,16 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
19
 
20
  $this->theme = get_option( 'stylesheet' );
21
 
22
- // populates nav menus locations
23
- // since WP 4.4, must be done before customize_register is fired
24
  add_filter( 'theme_mod_nav_menu_locations', array( $this, 'theme_mod_nav_menu_locations' ), 20 );
25
 
26
- // integration in the WP menu interface
27
  add_action( 'admin_init', array( $this, 'admin_init' ) ); // after Polylang upgrade
28
  }
29
 
30
  /**
31
- * setups filters and terms
32
  * adds the language switcher metabox and create new nav menu locations
33
  *
34
  * @since 1.1
@@ -38,11 +38,11 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
38
  add_action( 'wp_update_nav_menu_item', array( $this, 'wp_update_nav_menu_item' ), 10, 2 );
39
  add_filter( 'wp_get_nav_menu_items', array( $this, 'translate_switcher_title' ) );
40
 
41
- // translation of menus based on chosen locations
42
  add_filter( 'pre_update_option_theme_mods_' . $this->theme, array( $this, 'pre_update_option_theme_mods' ) );
43
  add_action( 'delete_nav_menu', array( $this, 'delete_nav_menu' ) );
44
 
45
- // filter _wp_auto_add_pages_to_menu by language
46
  add_action( 'transition_post_status', array( $this, 'auto_add_pages_to_menu' ), 5, 3 ); // before _wp_auto_add_pages_to_menu
47
 
48
  // FIXME is it possible to choose the order ( after theme locations in WP3.5 and older ) ?
@@ -53,16 +53,16 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
53
  }
54
 
55
  /**
56
- * language switcher metabox
57
  * The checkbox and all hidden fields are important
58
- * thanks to John Morris for his very interesting post http://www.johnmorrisonline.com/how-to-add-a-fully-functional-custom-meta-box-to-wordpress-navigation-menus/
59
  *
60
  * @since 1.1
61
  */
62
  public function lang_switch() {
63
  global $_nav_menu_placeholder, $nav_menu_selected_id;
64
- $_nav_menu_placeholder = 0 > $_nav_menu_placeholder ? $_nav_menu_placeholder - 1 : -1; ?>
65
-
66
  <div id="posttype-lang-switch" class="posttypediv">
67
  <div id="tabs-panel-lang-switch" class="tabs-panel tabs-panel-active">
68
  <ul id="lang-switch-checklist" class="categorychecklist form-no-clear">
@@ -73,20 +73,21 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
73
  <input type="hidden" class="menu-item-type" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-type]" value="custom">
74
  <input type="hidden" class="menu-item-title" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-title]" value="<?php esc_html_e( 'Language switcher', 'polylang' ); ?>">
75
  <input type="hidden" class="menu-item-url" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-url]" value="#pll_switcher">
76
- </li>
77
- </ul>
78
- </div>
79
- <p class="button-controls">
80
- <span class="add-to-menu">
81
- <input type="submit" <?php disabled( $nav_menu_selected_id, 0 ); ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-post-type-menu-item" id="submit-posttype-lang-switch">
82
- <span class="spinner"></span>
83
- </span>
84
- </p>
85
- </div><?php
 
86
  }
87
 
88
  /**
89
- * prepares javascript to modify the language switcher menu item
90
  *
91
  * @since 1.1
92
  */
@@ -99,10 +100,10 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
99
  $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
100
  wp_enqueue_script( 'pll_nav_menu', plugins_url( '/js/nav-menu' . $suffix . '.js', POLYLANG_FILE ), array( 'jquery' ), POLYLANG_VERSION );
101
 
102
- $data['strings'] = PLL_Switcher::get_switcher_options( 'menu', 'string' ); // the strings for the options
103
- $data['title'] = __( 'Language switcher', 'polylang' ); // the title
104
 
105
- // get all language switcher menu items
106
  $items = get_posts( array(
107
  'numberposts' => -1,
108
  'nopaging' => true,
@@ -111,18 +112,18 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
111
  'meta_key' => '_pll_menu_item',
112
  ) );
113
 
114
- // the options values for the language switcher
115
  $data['val'] = array();
116
  foreach ( $items as $item ) {
117
  $data['val'][ $item ] = get_post_meta( $item, '_pll_menu_item', true );
118
  }
119
 
120
- // send all these data to javascript
121
  wp_localize_script( 'pll_nav_menu', 'pll_data', $data );
122
  }
123
 
124
  /**
125
- * save our menu item options
126
  *
127
  * @since 1.1
128
  *
@@ -134,15 +135,14 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
134
  return;
135
  }
136
 
137
- // security check
138
- // as 'wp_update_nav_menu_item' can be called from outside WP admin
139
  if ( current_user_can( 'edit_theme_options' ) ) {
140
  check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
141
 
142
- $options = array( 'hide_if_no_translation' => 0, 'hide_current' => 0,'force_home' => 0 ,'show_flags' => 0 ,'show_names' => 1, 'dropdown' => 0 ); // default values
143
- // our jQuery form has not been displayed
144
  if ( empty( $_POST['menu-item-pll-detect'][ $menu_item_db_id ] ) ) {
145
- if ( ! get_post_meta( $menu_item_db_id, '_pll_menu_item', true ) ) { // our options were never saved
146
  update_post_meta( $menu_item_db_id, '_pll_menu_item', $options );
147
  }
148
  }
@@ -150,13 +150,13 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
150
  foreach ( $options as $opt => $v ) {
151
  $options[ $opt ] = empty( $_POST[ 'menu-item-' . $opt ][ $menu_item_db_id ] ) ? 0 : 1;
152
  }
153
- update_post_meta( $menu_item_db_id, '_pll_menu_item', $options ); // allow us to easily identify our nav menu item
154
  }
155
  }
156
  }
157
 
158
  /**
159
- * translates the language switcher menu items title in case the user switches the admin language
160
  *
161
  * @since 1.1.1
162
  *
@@ -173,7 +173,7 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
173
  }
174
 
175
  /**
176
- * assign menu languages and translations based on ( temporary ) locations
177
  *
178
  * @since 1.8
179
  *
@@ -183,12 +183,12 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
183
  public function update_nav_menu_locations( $locations ) {
184
  $default = $this->options['default_lang'];
185
 
186
- // extract language and menu from locations
187
  foreach ( $locations as $loc => $menu ) {
188
  $infos = $this->explode_location( $loc );
189
  $this->options['nav_menus'][ $this->theme ][ $infos['location'] ][ $infos['lang'] ] = $menu;
190
  if ( $this->options['default_lang'] != $infos['lang'] ) {
191
- unset( $locations[ $loc ] ); // remove temporary locations before database update
192
  }
193
  }
194
 
@@ -197,7 +197,7 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
197
  }
198
 
199
  /**
200
- * assign menu languages and translations based on ( temporary ) locations
201
  *
202
  * @since 1.1
203
  *
@@ -214,21 +214,21 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
214
  }
215
 
216
  // Edit Menus tab in Appearance -> Menus
217
- // add the test of $_POST['update-nav-menu-nonce'] to avoid conflict with Vantage theme
218
  elseif ( isset( $_POST['action'], $_POST['update-nav-menu-nonce'] ) && 'update' == $_POST['action'] ) {
219
  check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
220
  $this->options['nav_menus'][ $this->theme ] = array();
221
  }
222
 
223
- // customizer
224
- // don't reset locations in this case.
225
  // see http://wordpress.org/support/topic/menus-doesnt-show-and-not-saved-in-theme-settings-multilingual-site
226
  elseif ( isset( $_POST['action'] ) && 'customize_save' == $_POST['action'] ) {
227
  check_ajax_referer( 'save-customize_' . $GLOBALS['wp_customize']->get_stylesheet(), 'nonce' );
228
  }
229
 
230
  else {
231
- return $mods; // no modification for nav menu locations
232
  }
233
 
234
  $mods['nav_menu_locations'] = $this->update_nav_menu_locations( $mods['nav_menu_locations'] );
@@ -237,7 +237,7 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
237
  }
238
 
239
  /**
240
- * fills temporary menu locations based on menus translations
241
  *
242
  * @since 1.2
243
  *
@@ -245,6 +245,13 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
245
  * @return bool|array modified list of menu locations
246
  */
247
  public function theme_mod_nav_menu_locations( $menus ) {
 
 
 
 
 
 
 
248
  if ( is_array( $menus ) ) {
249
  foreach ( $menus as $loc => $menu ) {
250
  foreach ( $this->model->get_languages_list() as $lang ) {
@@ -259,11 +266,11 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
259
  }
260
 
261
  /**
262
- * removes the nav menu term_id from the locations stored in Polylang options when a nav menu is deleted
263
  *
264
  * @since 1.7.3
265
  *
266
- * @param int nav menu id
267
  */
268
  function delete_nav_menu( $term_id ) {
269
  if ( isset( $this->options['nav_menus'] ) ) {
@@ -282,9 +289,9 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
282
  }
283
 
284
  /**
285
- * filters the option nav_menu_options for auto added pages to menu
286
  *
287
- * @since 0.9.4
288
  *
289
  * @param array $options
290
  * @return array Modified options
@@ -295,7 +302,7 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
295
  }
296
 
297
  /**
298
- * filters _wp_auto_add_pages_to_menu by language
299
  *
300
  * @since 0.9.4
301
  *
@@ -310,8 +317,8 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
310
 
311
  if ( ! empty( $this->options['nav_menus'][ $this->theme ] ) ) {
312
  $this->auto_add_menus = array();
313
-
314
- // get all the menus in the page language
315
  foreach ( $this->options['nav_menus'][ $this->theme ] as $loc ) {
316
  if ( ! empty( $loc[ $lang->slug ] ) ) {
317
  $this->auto_add_menus[] = $loc[ $lang->slug ];
1
  <?php
2
 
3
  /**
4
+ * Manages custom menus translations as well as the language switcher menu item on admin side
5
  *
6
  * @since 1.2
7
  */
8
  class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
9
 
10
  /**
11
+ * Constructor: setups filters and actions
12
  *
13
  * @since 1.2
14
  *
19
 
20
  $this->theme = get_option( 'stylesheet' );
21
 
22
+ // Populates nav menus locations
23
+ // Since WP 4.4, must be done before customize_register is fired
24
  add_filter( 'theme_mod_nav_menu_locations', array( $this, 'theme_mod_nav_menu_locations' ), 20 );
25
 
26
+ // Integration in the WP menu interface
27
  add_action( 'admin_init', array( $this, 'admin_init' ) ); // after Polylang upgrade
28
  }
29
 
30
  /**
31
+ * Setups filters and terms
32
  * adds the language switcher metabox and create new nav menu locations
33
  *
34
  * @since 1.1
38
  add_action( 'wp_update_nav_menu_item', array( $this, 'wp_update_nav_menu_item' ), 10, 2 );
39
  add_filter( 'wp_get_nav_menu_items', array( $this, 'translate_switcher_title' ) );
40
 
41
+ // Translation of menus based on chosen locations
42
  add_filter( 'pre_update_option_theme_mods_' . $this->theme, array( $this, 'pre_update_option_theme_mods' ) );
43
  add_action( 'delete_nav_menu', array( $this, 'delete_nav_menu' ) );
44
 
45
+ // Filter _wp_auto_add_pages_to_menu by language
46
  add_action( 'transition_post_status', array( $this, 'auto_add_pages_to_menu' ), 5, 3 ); // before _wp_auto_add_pages_to_menu
47
 
48
  // FIXME is it possible to choose the order ( after theme locations in WP3.5 and older ) ?
53
  }
54
 
55
  /**
56
+ * Language switcher metabox
57
  * The checkbox and all hidden fields are important
58
+ * Thanks to John Morris for his very interesting post http://www.johnmorrisonline.com/how-to-add-a-fully-functional-custom-meta-box-to-wordpress-navigation-menus/
59
  *
60
  * @since 1.1
61
  */
62
  public function lang_switch() {
63
  global $_nav_menu_placeholder, $nav_menu_selected_id;
64
+ $_nav_menu_placeholder = 0 > $_nav_menu_placeholder ? $_nav_menu_placeholder - 1 : -1;
65
+ ?>
66
  <div id="posttype-lang-switch" class="posttypediv">
67
  <div id="tabs-panel-lang-switch" class="tabs-panel tabs-panel-active">
68
  <ul id="lang-switch-checklist" class="categorychecklist form-no-clear">
73
  <input type="hidden" class="menu-item-type" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-type]" value="custom">
74
  <input type="hidden" class="menu-item-title" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-title]" value="<?php esc_html_e( 'Language switcher', 'polylang' ); ?>">
75
  <input type="hidden" class="menu-item-url" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-url]" value="#pll_switcher">
76
+ </li>
77
+ </ul>
78
+ </div>
79
+ <p class="button-controls">
80
+ <span class="add-to-menu">
81
+ <input type="submit" <?php disabled( $nav_menu_selected_id, 0 ); ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-post-type-menu-item" id="submit-posttype-lang-switch">
82
+ <span class="spinner"></span>
83
+ </span>
84
+ </p>
85
+ </div>
86
+ <?php
87
  }
88
 
89
  /**
90
+ * Prepares javascript to modify the language switcher menu item
91
  *
92
  * @since 1.1
93
  */
100
  $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
101
  wp_enqueue_script( 'pll_nav_menu', plugins_url( '/js/nav-menu' . $suffix . '.js', POLYLANG_FILE ), array( 'jquery' ), POLYLANG_VERSION );
102
 
103
+ $data['strings'] = PLL_Switcher::get_switcher_options( 'menu', 'string' ); // The strings for the options
104
+ $data['title'] = __( 'Language switcher', 'polylang' ); // The title
105
 
106
+ // Get all language switcher menu items
107
  $items = get_posts( array(
108
  'numberposts' => -1,
109
  'nopaging' => true,
112
  'meta_key' => '_pll_menu_item',
113
  ) );
114
 
115
+ // The options values for the language switcher
116
  $data['val'] = array();
117
  foreach ( $items as $item ) {
118
  $data['val'][ $item ] = get_post_meta( $item, '_pll_menu_item', true );
119
  }
120
 
121
+ // Send all these data to javascript
122
  wp_localize_script( 'pll_nav_menu', 'pll_data', $data );
123
  }
124
 
125
  /**
126
+ * Save our menu item options
127
  *
128
  * @since 1.1
129
  *
135
  return;
136
  }
137
 
138
+ // Security check as 'wp_update_nav_menu_item' can be called from outside WP admin
 
139
  if ( current_user_can( 'edit_theme_options' ) ) {
140
  check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
141
 
142
+ $options = array( 'hide_if_no_translation' => 0, 'hide_current' => 0, 'force_home' => 0, 'show_flags' => 0, 'show_names' => 1, 'dropdown' => 0 ); // Default values
143
+ // Our jQuery form has not been displayed
144
  if ( empty( $_POST['menu-item-pll-detect'][ $menu_item_db_id ] ) ) {
145
+ if ( ! get_post_meta( $menu_item_db_id, '_pll_menu_item', true ) ) { // Our options were never saved
146
  update_post_meta( $menu_item_db_id, '_pll_menu_item', $options );
147
  }
148
  }
150
  foreach ( $options as $opt => $v ) {
151
  $options[ $opt ] = empty( $_POST[ 'menu-item-' . $opt ][ $menu_item_db_id ] ) ? 0 : 1;
152
  }
153
+ update_post_meta( $menu_item_db_id, '_pll_menu_item', $options ); // Allow us to easily identify our nav menu item
154
  }
155
  }
156
  }
157
 
158
  /**
159
+ * Translates the language switcher menu items title in case the user switches the admin language
160
  *
161
  * @since 1.1.1
162
  *
173
  }
174
 
175
  /**
176
+ * Assign menu languages and translations based on ( temporary ) locations
177
  *
178
  * @since 1.8
179
  *
183
  public function update_nav_menu_locations( $locations ) {
184
  $default = $this->options['default_lang'];
185
 
186
+ // Extract language and menu from locations
187
  foreach ( $locations as $loc => $menu ) {
188
  $infos = $this->explode_location( $loc );
189
  $this->options['nav_menus'][ $this->theme ][ $infos['location'] ][ $infos['lang'] ] = $menu;
190
  if ( $this->options['default_lang'] != $infos['lang'] ) {
191
+ unset( $locations[ $loc ] ); // Remove temporary locations before database update
192
  }
193
  }
194
 
197
  }
198
 
199
  /**
200
+ * Assign menu languages and translations based on ( temporary ) locations
201
  *
202
  * @since 1.1
203
  *
214
  }
215
 
216
  // Edit Menus tab in Appearance -> Menus
217
+ // Add the test of $_POST['update-nav-menu-nonce'] to avoid conflict with Vantage theme
218
  elseif ( isset( $_POST['action'], $_POST['update-nav-menu-nonce'] ) && 'update' == $_POST['action'] ) {
219
  check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
220
  $this->options['nav_menus'][ $this->theme ] = array();
221
  }
222
 
223
+ // Customizer
224
+ // Don't reset locations in this case.
225
  // see http://wordpress.org/support/topic/menus-doesnt-show-and-not-saved-in-theme-settings-multilingual-site
226
  elseif ( isset( $_POST['action'] ) && 'customize_save' == $_POST['action'] ) {
227
  check_ajax_referer( 'save-customize_' . $GLOBALS['wp_customize']->get_stylesheet(), 'nonce' );
228
  }
229
 
230
  else {
231
+ return $mods; // No modification for nav menu locations
232
  }
233
 
234
  $mods['nav_menu_locations'] = $this->update_nav_menu_locations( $mods['nav_menu_locations'] );
237
  }
238
 
239
  /**
240
+ * Fills temporary menu locations based on menus translations
241
  *
242
  * @since 1.2
243
  *
245
  * @return bool|array modified list of menu locations
246
  */
247
  public function theme_mod_nav_menu_locations( $menus ) {
248
+ // Prefill locations with 0 value in case a location does not exist in $menus
249
+ $locations = get_registered_nav_menus();
250
+ if ( is_array( $locations ) ) {
251
+ $locations = array_fill_keys( array_keys( $locations ), 0 );
252
+ $menus = is_array( $menus ) ? array_merge( $locations , $menus ) : $locations;
253
+ }
254
+
255
  if ( is_array( $menus ) ) {
256
  foreach ( $menus as $loc => $menu ) {
257
  foreach ( $this->model->get_languages_list() as $lang ) {
266
  }
267
 
268
  /**
269
+ * Removes the nav menu term_id from the locations stored in Polylang options when a nav menu is deleted
270
  *
271
  * @since 1.7.3
272
  *
273
+ * @param int $term_id nav menu id
274
  */
275
  function delete_nav_menu( $term_id ) {
276
  if ( isset( $this->options['nav_menus'] ) ) {
289
  }
290
 
291
  /**
292
+ * Filters the option nav_menu_options for auto added pages to menu
293
  *
294
+ * @since 0.9.4
295
  *
296
  * @param array $options
297
  * @return array Modified options
302
  }
303
 
304
  /**
305
+ * Filters _wp_auto_add_pages_to_menu by language
306
  *
307
  * @since 0.9.4
308
  *
317
 
318
  if ( ! empty( $this->options['nav_menus'][ $this->theme ] ) ) {
319
  $this->auto_add_menus = array();
320
+
321
+ // Get all the menus in the page language
322
  foreach ( $this->options['nav_menus'][ $this->theme ] as $loc ) {
323
  if ( ! empty( $loc[ $lang->slug ] ) ) {
324
  $this->auto_add_menus[] = $loc[ $lang->slug ];
admin/admin-static-pages.php CHANGED
@@ -1,14 +1,14 @@
1
  <?php
2
 
3
  /**
4
- * manages the static front page and the page for posts on admin side
5
  *
6
  * @since 1.8
7
  */
8
  class PLL_Admin_Static_Pages extends PLL_Static_Pages {
9
 
10
  /**
11
- * constructor: setups filters and actions
12
  *
13
  * @since 1.8
14
  *
@@ -17,25 +17,26 @@ class PLL_Admin_Static_Pages extends PLL_Static_Pages {
17
  public function __construct( &$polylang ) {
18
  parent::__construct( $polylang );
19
 
20
- // add post state for translations of the front page and posts page
21
  add_filter( 'display_post_states', array( $this, 'display_post_states' ), 10, 2 );
22
 
23
- // refresh language cache when a static front page has been translated
24
  add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
25
 
26
- // checks if chosen page on front is translated
27
  add_filter( 'pre_update_option_page_on_front', array( $this, 'update_page_on_front' ), 10, 2 );
 
28
 
29
  // Prevents WP resetting the option
30
  add_filter( 'pre_update_option_show_on_front', array( $this, 'update_show_on_front' ), 10, 2 );
31
  }
32
 
33
  /**
34
- * add post state for translations of the front page and posts page
35
  *
36
  * @since 1.8
37
  *
38
- * @param array $post_states
39
  * @param object $post
40
  * @return array
41
  */
@@ -52,13 +53,13 @@ class PLL_Admin_Static_Pages extends PLL_Static_Pages {
52
  }
53
 
54
  /**
55
- * refresh language cache when a static front page has been translated
56
  *
57
  * @since 1.8
58
  *
59
- * @param int $post_id not used
60
- * @param object $post not used
61
- * @param array $translations
62
  */
63
  public function pll_save_post( $post_id, $post, $translations ) {
64
  if ( in_array( $this->page_on_front, $translations ) ) {
@@ -67,29 +68,62 @@ class PLL_Admin_Static_Pages extends PLL_Static_Pages {
67
  }
68
 
69
  /**
70
- * prevents choosing an untranslated static front page
71
- * displays an error message
72
  *
73
- * @since 1.6
74
  *
75
- * @param int $page_id new page on front page id
76
- * @param int $old_id old page on front page_id
77
- * @return int
78
  */
79
- public function update_page_on_front( $page_id, $old_id ) {
80
  if ( $page_id ) {
81
  $translations = count( $this->model->post->get_translations( $page_id ) );
82
  $languages = count( $this->model->get_languages_list() );
83
 
84
  if ( $languages > 1 && $translations != $languages ) {
85
- $page_id = $old_id;
86
- add_settings_error( 'reading', 'pll_page_on_front_error', __( 'The chosen static front page must be translated in all languages.', 'polylang' ) );
87
  }
88
  }
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  return $page_id;
91
  }
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  /**
94
  * Prevents WP resetting the option if the admin language filter is active for a language with no pages
95
  *
1
  <?php
2
 
3
  /**
4
+ * Manages the static front page and the page for posts on admin side
5
  *
6
  * @since 1.8
7
  */
8
  class PLL_Admin_Static_Pages extends PLL_Static_Pages {
9
 
10
  /**
11
+ * Constructor: setups filters and actions
12
  *
13
  * @since 1.8
14
  *
17
  public function __construct( &$polylang ) {
18
  parent::__construct( $polylang );
19
 
20
+ // Add post state for translations of the front page and posts page
21
  add_filter( 'display_post_states', array( $this, 'display_post_states' ), 10, 2 );
22
 
23
+ // Refresh language cache when a static front page has been translated
24
  add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
25
 
26
+ // Checks if chosen page on front is translated
27
  add_filter( 'pre_update_option_page_on_front', array( $this, 'update_page_on_front' ), 10, 2 );
28
+ add_filter( 'customize_validate_page_on_front', array( $this, 'customize_validate_page_on_front' ), 10, 2 );
29
 
30
  // Prevents WP resetting the option
31
  add_filter( 'pre_update_option_show_on_front', array( $this, 'update_show_on_front' ), 10, 2 );
32
  }
33
 
34
  /**
35
+ * Add post state for translations of the front page and posts page
36
  *
37
  * @since 1.8
38
  *
39
+ * @param array $post_states
40
  * @param object $post
41
  * @return array
42
  */
53
  }
54
 
55
  /**
56
+ * Refresh language cache when a static front page has been translated
57
  *
58
  * @since 1.8
59
  *
60
+ * @param int $post_id Not used
61
+ * @param object $post Not used
62
+ * @param array $translations
63
  */
64
  public function pll_save_post( $post_id, $post, $translations ) {
65
  if ( in_array( $this->page_on_front, $translations ) ) {
68
  }
69
 
70
  /**
71
+ * Checks if a page is translted in all languages
 
72
  *
73
+ * @since 2.2
74
  *
75
+ * @param int $page_id
76
+ * @return bool
 
77
  */
78
+ protected function is_page_translated( $page_id ) {
79
  if ( $page_id ) {
80
  $translations = count( $this->model->post->get_translations( $page_id ) );
81
  $languages = count( $this->model->get_languages_list() );
82
 
83
  if ( $languages > 1 && $translations != $languages ) {
84
+ return false;
 
85
  }
86
  }
87
 
88
+ return true;
89
+ }
90
+
91
+ /**
92
+ * Prevents choosing an untranslated static front page
93
+ * Displays an error message
94
+ *
95
+ * @since 1.6
96
+ *
97
+ * @param int $page_id New page on front page id
98
+ * @param int $old_id Old page on front page_id
99
+ * @return int
100
+ */
101
+ public function update_page_on_front( $page_id, $old_id ) {
102
+ if ( ! $this->is_page_translated( $page_id ) ) {
103
+ $page_id = $old_id;
104
+ add_settings_error( 'reading', 'pll_page_on_front_error', __( 'The chosen static front page must be translated in all languages.', 'polylang' ) );
105
+ }
106
+
107
  return $page_id;
108
  }
109
 
110
+ /**
111
+ * Displays an error message in the customizer when choosing an untranslated static front page
112
+ *
113
+ * @since 2.2
114
+ *
115
+ * @param object $validity WP_Error object
116
+ * @param int $page_id New page on front page id
117
+ * @return object
118
+ */
119
+ public function customize_validate_page_on_front( $validity, $page_id ) {
120
+ if ( ! $this->is_page_translated( $page_id ) ) {
121
+ return new WP_Error( 'pll_page_on_front_error', __( 'The chosen static front page must be translated in all languages.', 'polylang' ) );
122
+ }
123
+
124
+ return $validity;
125
+ }
126
+
127
  /**
128
  * Prevents WP resetting the option if the admin language filter is active for a language with no pages
129
  *
admin/admin-strings.php CHANGED
@@ -24,10 +24,10 @@ class PLL_Admin_Strings {
24
  *
25
  * @since 0.6
26
  *
27
- * @param string $name a unique name for the string
28
- * @param string $string the string to register
29
- * @param string $context optional the group in which the string is registered, defaults to 'polylang'
30
- * @param bool $multiline optional wether the string table should display a multiline textarea or a single line input, defaults to single line
31
  */
32
  static public function register_string( $name, $string, $context = 'Polylang', $multiline = false ) {
33
  // backward compatibility with Polylang older than 1.1
24
  *
25
  * @since 0.6
26
  *
27
+ * @param string $name A unique name for the string
28
+ * @param string $string The string to register
29
+ * @param string $context Optional, the group in which the string is registered, defaults to 'polylang'
30
+ * @param bool $multiline Optional, whether the string table should display a multiline textarea or a single line input, defaults to single line
31
  */
32
  static public function register_string( $name, $string, $context = 'Polylang', $multiline = false ) {
33
  // backward compatibility with Polylang older than 1.1
admin/admin.php CHANGED
@@ -47,8 +47,6 @@ class PLL_Admin extends PLL_Admin_Base {
47
  * loads the settings pages or the filters base on the request
48
  *
49
  * @since 1.2
50
- *
51
- * @param object $links_model
52
  */
53
  public function init() {
54
  parent::init();
@@ -78,8 +76,8 @@ class PLL_Admin extends PLL_Admin_Base {
78
  *
79
  * @since 1.1.6
80
  *
81
- * @param array $plugin_data not used
82
- * @param object $r plugin update data
83
  */
84
  function plugin_update_message( $plugin_data, $r ) {
85
  if ( isset( $r->upgrade_notice ) ) {
47
  * loads the settings pages or the filters base on the request
48
  *
49
  * @since 1.2
 
 
50
  */
51
  public function init() {
52
  parent::init();
76
  *
77
  * @since 1.1.6
78
  *
79
+ * @param array $plugin_data Not used
80
+ * @param object $r Plugin update data
81
  */
82
  function plugin_update_message( $plugin_data, $r ) {
83
  if ( isset( $r->upgrade_notice ) ) {
admin/view-translations-media.php CHANGED
@@ -1,25 +1,27 @@
1
  <?php
2
 
3
  /**
4
- * displays the translations fields for media
5
- * needs WP 3.5+
6
  */
7
 
8
  if ( ! defined( 'ABSPATH' ) ) {
9
- exit; // don't access directly
10
  };
11
  ?>
12
- <p><strong><?php esc_html_e( 'Translations', 'polylang' );?></strong></p>
13
- <table><?php
 
14
  foreach ( $this->model->get_languages_list() as $language ) {
15
  if ( $language->term_id == $lang->term_id ) {
16
  continue;
17
- }?>
18
-
19
  <tr>
20
  <td class = "pll-media-language-column"><span class = "pll-translation-flag"><?php echo $language->flag; ?></span><?php echo esc_html( $language->name ); ?></td>
21
- <td class = "pll-media-edit-column"><?php
22
- // the translation exists
 
23
  if ( ( $translation_id = $this->model->post->get_translation( $post_id, $language ) ) && $translation_id !== $post_id ) {
24
  printf(
25
  '<input type="hidden" name="media_tr_lang[%s]" value="%d" />%s',
@@ -29,11 +31,14 @@ if ( ! defined( 'ABSPATH' ) ) {
29
  );
30
  }
31
 
32
- // no translation
33
  else {
34
  echo $this->links->new_post_translation_link( $post_id, $language );
35
- }?>
 
36
  </td>
37
- </tr><?php
38
- } // foreach ?>
 
 
39
  </table>
1
  <?php
2
 
3
  /**
4
+ * Displays the translations fields for media
5
+ * Needs WP 3.5+
6
  */
7
 
8
  if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Don't access directly
10
  };
11
  ?>
12
+ <p><strong><?php esc_html_e( 'Translations', 'polylang' ); ?></strong></p>
13
+ <table>
14
+ <?php
15
  foreach ( $this->model->get_languages_list() as $language ) {
16
  if ( $language->term_id == $lang->term_id ) {
17
  continue;
18
+ }
19
+ ?>
20
  <tr>
21
  <td class = "pll-media-language-column"><span class = "pll-translation-flag"><?php echo $language->flag; ?></span><?php echo esc_html( $language->name ); ?></td>
22
+ <td class = "pll-media-edit-column">
23
+ <?php
24
+ // The translation exists
25
  if ( ( $translation_id = $this->model->post->get_translation( $post_id, $language ) ) && $translation_id !== $post_id ) {
26
  printf(
27
  '<input type="hidden" name="media_tr_lang[%s]" value="%d" />%s',
31
  );
32
  }
33
 
34
+ // No translation
35
  else {
36
  echo $this->links->new_post_translation_link( $post_id, $language );
37
+ }
38
+ ?>
39
  </td>
40
+ </tr>
41
+ <?php
42
+ } // End foreach
43
+ ?>
44
  </table>
admin/view-translations-post.php CHANGED
@@ -9,7 +9,8 @@ if ( ! defined( 'ABSPATH' ) ) {
9
  };
10
  ?>
11
  <p><strong><?php esc_html_e( 'Translations', 'polylang' ); ?></strong></p>
12
- <table><?php
 
13
  foreach ( $this->model->get_languages_list() as $language ) {
14
  if ( $language->term_id == $lang->term_id ) {
15
  continue;
@@ -29,12 +30,13 @@ if ( ! defined( 'ABSPATH' ) ) {
29
  if ( $value ) {
30
  $selected = get_post( $value );
31
  $link = $this->links->edit_post_translation_link( $value );
32
- } ?>
33
-
34
  <tr>
35
  <th class = "pll-language-column"><?php echo $language->flag ? $language->flag : esc_html( $language->slug ); ?></th>
36
- <td class = "hidden"><?php echo $add_link;?></td>
37
- <td class = "pll-edit-column pll-column-icon"><?php echo $link;?></td><?php
 
38
 
39
  /**
40
  * Fires before the translation colummn is outputed in the language metabox
@@ -42,20 +44,27 @@ if ( ! defined( 'ABSPATH' ) ) {
42
  *
43
  * @since 2.1
44
  */
45
- do_action( 'pll_before_post_translation_' . $language->slug ); ?>
46
- <td class = "pll-translation-column"><?php
 
 
47
  printf( '
48
  <label class="screen-reader-text" for="tr_lang_%1$s">%2$s</label>
49
  <input type="hidden" name="post_tr_lang[%1$s]" id="htr_lang_%1$s" value="%3$s" />
50
- <input type="text" class="tr_lang" id="tr_lang_%1$s" value="%4$s"%5$s />',
51
  esc_attr( $language->slug ),
52
  /* translators: accessibility text */
53
  esc_html__( 'Translation', 'polylang' ),
54
  empty( $value ) ? 0 : esc_attr( $selected->ID ),
55
  empty( $value ) ? '' : esc_attr( $selected->post_title ),
56
- empty( $link ) ? ' disabled="disabled"' : ''
57
- ); ?>
 
 
 
58
  </td>
59
- </tr><?php
60
- }?>
 
 
61
  </table>
9
  };
10
  ?>
11
  <p><strong><?php esc_html_e( 'Translations', 'polylang' ); ?></strong></p>
12
+ <table>
13
+ <?php
14
  foreach ( $this->model->get_languages_list() as $language ) {
15
  if ( $language->term_id == $lang->term_id ) {
16
  continue;
30
  if ( $value ) {
31
  $selected = get_post( $value );
32
  $link = $this->links->edit_post_translation_link( $value );
33
+ }
34
+ ?>
35
  <tr>
36
  <th class = "pll-language-column"><?php echo $language->flag ? $language->flag : esc_html( $language->slug ); ?></th>
37
+ <td class = "hidden"><?php echo $add_link; ?></td>
38
+ <td class = "pll-edit-column pll-column-icon"><?php echo $link; ?></td>
39
+ <?php
40
 
41
  /**
42
  * Fires before the translation colummn is outputed in the language metabox
44
  *
45
  * @since 2.1
46
  */
47
+ do_action( 'pll_before_post_translation_' . $language->slug );
48
+ ?>
49
+ <td class = "pll-translation-column">
50
+ <?php
51
  printf( '
52
  <label class="screen-reader-text" for="tr_lang_%1$s">%2$s</label>
53
  <input type="hidden" name="post_tr_lang[%1$s]" id="htr_lang_%1$s" value="%3$s" />
54
+ <span lang="%6$s" dir="%7$s"><input type="text" class="tr_lang" id="tr_lang_%1$s" value="%4$s"%5$s /></span>',
55
  esc_attr( $language->slug ),
56
  /* translators: accessibility text */
57
  esc_html__( 'Translation', 'polylang' ),
58
  empty( $value ) ? 0 : esc_attr( $selected->ID ),
59
  empty( $value ) ? '' : esc_attr( $selected->post_title ),
60
+ empty( $link ) ? ' disabled="disabled"' : '',
61
+ esc_attr( $language->get_locale( 'display' ) ),
62
+ $language->is_rtl ? 'rtl' : 'ltr'
63
+ );
64
+ ?>
65
  </td>
66
+ </tr>
67
+ <?php
68
+ }
69
+ ?>
70
  </table>
admin/view-translations-term.php CHANGED
@@ -1,30 +1,35 @@
1
  <?php
2
 
3
  /**
4
- * displays the translations fields for terms
5
  */
6
 
7
  if ( ! defined( 'ABSPATH' ) ) {
8
- exit; // don't access directly
9
  };
10
 
11
  if ( isset( $term_id ) ) {
12
- // edit term form ?>
13
  <th scope="row"><?php esc_html_e( 'Translations', 'polylang' ); ?></th>
14
- <td><?php
 
15
  }
16
  else {
17
- // add term form ?>
18
- <p><?php esc_html_e( 'Translations', 'polylang' ); ?></p><?php
19
- }?>
20
- <table class="widefat term-translations" id="<?php echo isset( $term_id ) ? 'edit' : 'add'; ?>-term-translations"><?php
 
 
 
 
21
  foreach ( $this->model->get_languages_list() as $language ) {
22
  if ( $language->term_id == $lang->term_id ) {
23
  continue;
24
  }
25
 
26
- // look for any existing translation in this language
27
- // take care not ot propose a self link
28
  $translation = 0;
29
  if ( isset( $term_id ) && ( $translation_id = $this->model->term->get_translation( $term_id, $language ) ) && $translation_id != $term_id ) {
30
  $translation = get_term( $translation_id, $taxonomy );
@@ -33,45 +38,60 @@ else {
33
  $translation = get_term( $translation_id, $taxonomy );
34
  }
35
 
36
- if ( isset( $term_id ) ) { // do not display the add new link in add term form ( $term_id not set !!! )
37
  $link = $add_link = $this->links->new_term_translation_link( $term_id, $taxonomy, $post_type, $language );
38
  }
39
 
40
  if ( $translation ) {
41
  $link = $this->links->edit_term_translation_link( $translation->term_id, $taxonomy, $post_type );
42
- } ?>
43
-
44
  <tr>
45
  <th class = "pll-language-column">
46
- <span class = "pll-translation-flag"><?php echo $language->flag; ?></span><?php
 
47
  printf(
48
  '<span class="pll-language-name%1$s">%2$s</span>',
49
  isset( $term_id ) ? '' : ' screen-reader-text',
50
  esc_html( $language->name )
51
- ); ?>
52
- </th> <?php
53
- if ( isset( $term_id ) ) { ?>
54
- <td class = "hidden"><?php echo $add_link;?></td>
55
- <td class = "pll-edit-column"><?php echo $link;?></td><?php
56
- } ?>
57
- <td class = "pll-translation-column"><?php
 
 
 
 
 
 
58
  printf( '
59
  <label class="screen-reader-text" for="tr_lang_%1$s">%2$s</label>
60
  <input type="hidden" class="htr_lang" name="term_tr_lang[%1$s]" id="htr_lang_%1$s" value="%3$s" />
61
- <input type="text" class="tr_lang" id="tr_lang_%1$s" value="%4$s"%5$s />',
62
  esc_attr( $language->slug ),
63
  /* translators: accessibility text */
64
  esc_html__( 'Translation', 'polylang' ),
65
  empty( $translation ) ? 0 : esc_attr( $translation->term_id ),
66
  empty( $translation ) ? '' : esc_attr( $translation->name ),
67
- empty( $disabled ) ? '' : ' disabled="disabled"'
68
- ); ?>
 
 
 
69
  </td>
70
- </tr><?php
71
- } // foreach ?>
72
- </table><?php
 
 
 
73
 
74
  if ( isset( $term_id ) ) {
75
- // edit term form?>
76
- </td><?php
 
 
77
  }
1
  <?php
2
 
3
  /**
4
+ * Displays the translations fields for terms
5
  */
6
 
7
  if ( ! defined( 'ABSPATH' ) ) {
8
+ exit; // Don't access directly
9
  };
10
 
11
  if ( isset( $term_id ) ) {
12
+ // Edit term form ?>
13
  <th scope="row"><?php esc_html_e( 'Translations', 'polylang' ); ?></th>
14
+ <td>
15
+ <?php
16
  }
17
  else {
18
+ // Add term form
19
+ ?>
20
+ <p><?php esc_html_e( 'Translations', 'polylang' ); ?></p>
21
+ <?php
22
+ }
23
+ ?>
24
+ <table class="widefat term-translations" id="<?php echo isset( $term_id ) ? 'edit' : 'add'; ?>-term-translations">
25
+ <?php
26
  foreach ( $this->model->get_languages_list() as $language ) {
27
  if ( $language->term_id == $lang->term_id ) {
28
  continue;
29
  }
30
 
31
+ // Look for any existing translation in this language
32
+ // Take care not to propose a self link
33
  $translation = 0;
34
  if ( isset( $term_id ) && ( $translation_id = $this->model->term->get_translation( $term_id, $language ) ) && $translation_id != $term_id ) {
35
  $translation = get_term( $translation_id, $taxonomy );
38
  $translation = get_term( $translation_id, $taxonomy );
39
  }
40
 
41
+ if ( isset( $term_id ) ) { // Do not display the add new link in add term form ( $term_id not set !!! )
42
  $link = $add_link = $this->links->new_term_translation_link( $term_id, $taxonomy, $post_type, $language );
43
  }
44
 
45
  if ( $translation ) {
46
  $link = $this->links->edit_term_translation_link( $translation->term_id, $taxonomy, $post_type );
47
+ }
48
+ ?>
49
  <tr>
50
  <th class = "pll-language-column">
51
+ <span class = "pll-translation-flag"><?php echo $language->flag; ?></span>
52
+ <?php
53
  printf(
54
  '<span class="pll-language-name%1$s">%2$s</span>',
55
  isset( $term_id ) ? '' : ' screen-reader-text',
56
  esc_html( $language->name )
57
+ );
58
+ ?>
59
+ </th>
60
+ <?php
61
+ if ( isset( $term_id ) ) {
62
+ ?>
63
+ <td class = "hidden"><?php echo $add_link; ?></td>
64
+ <td class = "pll-edit-column"><?php echo $link; ?></td>
65
+ <?php
66
+ }
67
+ ?>
68
+ <td class = "pll-translation-column">
69
+ <?php
70
  printf( '
71
  <label class="screen-reader-text" for="tr_lang_%1$s">%2$s</label>
72
  <input type="hidden" class="htr_lang" name="term_tr_lang[%1$s]" id="htr_lang_%1$s" value="%3$s" />
73
+ <span lang="%6$s" dir="%7$s"><input type="text" class="tr_lang" id="tr_lang_%1$s" value="%4$s"%5$s /></span>',
74
  esc_attr( $language->slug ),
75
  /* translators: accessibility text */
76
  esc_html__( 'Translation', 'polylang' ),
77
  empty( $translation ) ? 0 : esc_attr( $translation->term_id ),
78
  empty( $translation ) ? '' : esc_attr( $translation->name ),
79
+ empty( $disabled ) ? '' : ' disabled="disabled"',
80
+ esc_attr( $language->get_locale( 'display' ) ),
81
+ $language->is_rtl ? 'rtl' : 'ltr'
82
+ );
83
+ ?>
84
  </td>
85
+ </tr>
86
+ <?php
87
+ } // End foreach
88
+ ?>
89
+ </table>
90
+ <?php
91
 
92
  if ( isset( $term_id ) ) {
93
+ // Edit term form
94
+ ?>
95
+ </td>
96
+ <?php
97
  }
changelog.txt CHANGED
@@ -145,7 +145,7 @@ This file contains only old changelog. See readme.txt for newer versions.
145
  = 1.9 (2016-04-27) =
146
 
147
  * Pro: add the possibility to translate custom post types slugs, taxonomies slugs and more
148
- * Pro: add the possibility to share the same post or term slug accross languages
149
  * Pro: add the possibility to duplicate the content when creating a new translation
150
  * Pro: add the possibility to create all translations at once when uploading a media
151
  * Pro: add the possibility to disable a language
@@ -676,7 +676,7 @@ This version does include important changes in database. More than ever, make a
676
  * Change the language and translations model from meta to taxonomy (no extra termmeta table created anymore)
677
  * Move the strings translations from option to a custom post type
678
  * Add support for language code in subdomain and for one different domain per language (experimental)
679
- * Add support of wordpress importer plugin. Export must have been done with Polylang 1.2+ (experimental)
680
  * Add support for theme navigation customizer (was de-activated by Polylang since WP 3.4)
681
  * Request confirmation for deleting a language
682
  * Better management of default category for each language
145
  = 1.9 (2016-04-27) =
146
 
147
  * Pro: add the possibility to translate custom post types slugs, taxonomies slugs and more
148
+ * Pro: add the possibility to share the same post or term slug across languages
149
  * Pro: add the possibility to duplicate the content when creating a new translation
150
  * Pro: add the possibility to create all translations at once when uploading a media
151
  * Pro: add the possibility to disable a language
676
  * Change the language and translations model from meta to taxonomy (no extra termmeta table created anymore)
677
  * Move the strings translations from option to a custom post type
678
  * Add support for language code in subdomain and for one different domain per language (experimental)
679
+ * Add support of WordPress Importer plugin. Export must have been done with Polylang 1.2+ (experimental)
680
  * Add support for theme navigation customizer (was de-activated by Polylang since WP 3.4)
681
  * Request confirmation for deleting a language
682
  * Better management of default category for each language
css/admin.css CHANGED
@@ -148,6 +148,21 @@ td[class*='column-language_'] {
148
  width: 1.5em;
149
  }
150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
  /* languages metabox in post.php */
153
  #post-translations p {
148
  width: 1.5em;
149
  }
150
 
151
+ /* Text direcction in post.php and edit-tags.php */
152
+ .pll-dir-rtl textarea,
153
+ .pll-dir-rtl input[type="text"] {
154
+ direction: rtl;
155
+ }
156
+
157
+ .pll-dir-ltr textarea,
158
+ .pll-dir-ltr input[type="text"] {
159
+ direction: ltr;
160
+ }
161
+
162
+ .pll-dir-ltr .tr_lang,
163
+ .pll-dir-rtl .tr_lang {
164
+ direction: inherit;
165
+ }
166
 
167
  /* languages metabox in post.php */
168
  #post-translations p {
css/admin.min.css CHANGED
@@ -1 +1 @@
1
- #pll-licenses-table td,.translation label{vertical-align:top}#add-lang select{width:95%}.column-locale,.languages .column-slug{width:15%}.column-default_lang{width:5%}.column-count,.column-flag,.column-term_group{width:10%}.icon-default-lang:before{font-family:dashicons;content:"\f155"}.form-field input[type=radio]{width:auto;margin-right:2px}#pll-about-box p,#pll-recommended p{text-align:justify}#pll-about-box input{margin:0;padding:0;float:right}.stringstranslations .column-context,.stringstranslations .column-name{width:10%}.stringstranslations .column-string{width:33%}.translation label{display:inline-block;width:23%}.translation input,.translation textarea{width:72%}.pll-settings{margin-top:20px}.pll-settings .plugin-title{width:25%}#wpbody-content .pll-settings .pll-configure tr{display:table-row}#wpbody-content .pll-settings .pll-configure td{display:table-cell}#wpbody-content .pll-settings .pll-configure>td{padding:20px 20px 20px 40px}.pll-configure legend{font-size:14px;font-weight:600;margin-bottom:.5em}.pll-configure td .description{margin-top:2px;margin-bottom:.5em}.pll-configure p.submit{margin-top:20px}.pll-configure .button{margin-right:20px}.pll-configure fieldset{margin-bottom:1.5em}.pll-inline-block-list{margin:0}.pll-inline-block-list li{display:inline-block;margin:0;width:250px}#pll-domains-table td{padding:2px 2px 2px 1.5em;-webkit-box-shadow:none;box-shadow:none;border:none}.pll-settings-url-col{display:inline-block;width:49%;vertical-align:top}#pll-licenses-table label{font-size:1em;font-weight:600}.pll-configure .pll-deactivate-license{margin:0 0 0 20px}td[class*=column-language_],th[class*=column-language_]{width:1.5em}#post-translations p{float:left}#post-translations table{table-layout:fixed;width:100%;clear:both}#post-translations a{text-decoration:none}#post-translations .pll-column-icon,#post-translations .pll-language-column{width:20px}#post-translations .tr_lang{width:100%}#post-translations td{padding:2px}#post-translations .spinner,#term-translations .spinner{float:none;margin:0;background-position:center;width:auto}.pll-column-icon{text-align:center}#select-post-language .pll-select-flag{padding:4px;margin-right:32px}#select-media-language .pll-select-flag{padding:4px;margin-right:10px}.pll-media-edit-column{float:right}.pll-translation-flag{margin-right:14px}#select-add-term-language .pll-select-flag{padding:11px;margin-right:13px}#select-edit-term-language .pll-select-flag{padding:11px;margin-right:4px}#term-translations p{font-size:12px;font-style:normal;padding:2px;color:#23282d}#add-term-translations,#edit-term-translations{width:95%}#term-translations .pll-language-column{line-height:28px;width:20%}#add-term-translations .pll-language-column,#term-translations .pll-edit-column{width:20px}#edit-term-translations .pll-language-column{padding:15px 10px;font-weight:400}.pll_icon_tick:before{content:"\f147"}.pll_icon_add:before{content:"\f132"}.pll_icon_edit:before{content:"\f464"}[class^=pll_icon_]{font:20px/1 dashicons;vertical-align:middle}#wpadminbar #wp-admin-bar-languages .ab-item img{margin:0 8px 0 2px}#wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon{float:none;top:4px}#wpadminbar #wp-admin-bar-languages .ab-icon:before{content:"\f326";top:1px}@media screen and (max-width:782px){#wpbody-content .pll-settings .pll-configure>td{padding:20px}#wpbody-content .pll-settings #cb{padding:20px 9px}.pll-inline-block{width:auto}.pll-settings-url-col{display:block;width:100%}#wpbody-content .pll-settings #pll-licenses-table td{display:block}.pll-configure .pll-deactivate-license{margin:10px 0 5px}.stringstranslations .column-context,.stringstranslations .column-name{display:none}.translation label{display:block;width:95%;padding-left:0}.translation input{width:95%}#edit-term-translations .pll-language-name,#select-add-term-language .pll-select-flag,#select-edit-term-language .pll-select-flag{display:none}#edit-term-translations{width:100%}#add-term-translations .pll-language-column{line-height:38px}#edit-term-translations td{padding:8px 10px}#edit-term-translations .pll-edit-column,#edit-term-translations .pll-language-column{width:20px}.term-translations .pll-edit-column,.term-translations .pll-language-column,.term-translations .pll-translation-column{display:table-cell}.term-translations .hidden{display:none}#wpadminbar #wp-admin-bar-languages{display:block}#wpadminbar #wp-admin-bar-languages>.ab-item{width:50px;text-align:center}#wpadminbar #wp-admin-bar-languages>.ab-item .ab-icon:before{font:32px/1 dashicons;top:-1px}#wpadminbar #wp-admin-bar-languages>.ab-item img{margin:19px 0}#wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon{margin-right:6px;font-size:20px!important;line-height:20px!important}}
1
+ #pll-licenses-table td,.translation label{vertical-align:top}#add-lang select{width:95%}.column-locale,.languages .column-slug{width:15%}.column-default_lang{width:5%}.column-count,.column-flag,.column-term_group{width:10%}.icon-default-lang:before{font-family:dashicons;content:"\f155"}.form-field input[type=radio]{width:auto;margin-right:2px}#pll-about-box p,#pll-recommended p{text-align:justify}#pll-about-box input{margin:0;padding:0;float:right}.stringstranslations .column-context,.stringstranslations .column-name{width:10%}.stringstranslations .column-string{width:33%}.translation label{display:inline-block;width:23%}.translation input,.translation textarea{width:72%}.pll-settings{margin-top:20px}.pll-settings .plugin-title{width:25%}#wpbody-content .pll-settings .pll-configure tr{display:table-row}#wpbody-content .pll-settings .pll-configure td{display:table-cell}#wpbody-content .pll-settings .pll-configure>td{padding:20px 20px 20px 40px}.pll-configure legend{font-size:14px;font-weight:600;margin-bottom:.5em}.pll-configure td .description{margin-top:2px;margin-bottom:.5em}.pll-configure p.submit{margin-top:20px}.pll-configure .button{margin-right:20px}.pll-configure fieldset{margin-bottom:1.5em}.pll-inline-block-list{margin:0}.pll-inline-block-list li{display:inline-block;margin:0;width:250px}#pll-domains-table td{padding:2px 2px 2px 1.5em;-webkit-box-shadow:none;box-shadow:none;border:none}.pll-settings-url-col{display:inline-block;width:49%;vertical-align:top}#pll-licenses-table label{font-size:1em;font-weight:600}.pll-configure .pll-deactivate-license{margin:0 0 0 20px}td[class*=column-language_],th[class*=column-language_]{width:1.5em}.pll-dir-rtl input[type=text],.pll-dir-rtl textarea{direction:rtl}.pll-dir-ltr input[type=text],.pll-dir-ltr textarea{direction:ltr}.pll-dir-ltr .tr_lang,.pll-dir-rtl .tr_lang{direction:inherit}#post-translations p{float:left}#post-translations table{table-layout:fixed;width:100%;clear:both}#post-translations a{text-decoration:none}#post-translations .pll-column-icon,#post-translations .pll-language-column{width:20px}#post-translations .tr_lang{width:100%}#post-translations td{padding:2px}#post-translations .spinner,#term-translations .spinner{float:none;margin:0;background-position:center;width:auto}.pll-column-icon{text-align:center}#select-post-language .pll-select-flag{padding:4px;margin-right:32px}#select-media-language .pll-select-flag{padding:4px;margin-right:10px}.pll-media-edit-column{float:right}.pll-translation-flag{margin-right:14px}#select-add-term-language .pll-select-flag{padding:11px;margin-right:13px}#select-edit-term-language .pll-select-flag{padding:11px;margin-right:4px}#term-translations p{font-size:12px;font-style:normal;padding:2px;color:#23282d}#add-term-translations,#edit-term-translations{width:95%}#term-translations .pll-language-column{line-height:28px;width:20%}#add-term-translations .pll-language-column,#term-translations .pll-edit-column{width:20px}#edit-term-translations .pll-language-column{padding:15px 10px;font-weight:400}.pll_icon_tick:before{content:"\f147"}.pll_icon_add:before{content:"\f132"}.pll_icon_edit:before{content:"\f464"}[class^=pll_icon_]{font:20px/1 dashicons;vertical-align:middle}#wpadminbar #wp-admin-bar-languages .ab-item img{margin:0 8px 0 2px}#wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon{float:none;top:4px}#wpadminbar #wp-admin-bar-languages .ab-icon:before{content:"\f326";top:1px}@media screen and (max-width:782px){#wpbody-content .pll-settings .pll-configure>td{padding:20px}#wpbody-content .pll-settings #cb{padding:20px 9px}.pll-inline-block{width:auto}.pll-settings-url-col{display:block;width:100%}#wpbody-content .pll-settings #pll-licenses-table td{display:block}.pll-configure .pll-deactivate-license{margin:10px 0 5px}.stringstranslations .column-context,.stringstranslations .column-name{display:none}.translation label{display:block;width:95%;padding-left:0}.translation input{width:95%}#edit-term-translations .pll-language-name,#select-add-term-language .pll-select-flag,#select-edit-term-language .pll-select-flag{display:none}#edit-term-translations{width:100%}#add-term-translations .pll-language-column{line-height:38px}#edit-term-translations td{padding:8px 10px}#edit-term-translations .pll-edit-column,#edit-term-translations .pll-language-column{width:20px}.term-translations .pll-edit-column,.term-translations .pll-language-column,.term-translations .pll-translation-column{display:table-cell}.term-translations .hidden{display:none}#wpadminbar #wp-admin-bar-languages{display:block}#wpadminbar #wp-admin-bar-languages>.ab-item{width:50px;text-align:center}#wpadminbar #wp-admin-bar-languages>.ab-item .ab-icon:before{font:32px/1 dashicons;top:-1px}#wpadminbar #wp-admin-bar-languages>.ab-item img{margin:19px 0}#wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon{margin-right:6px;font-size:20px!important;line-height:20px!important}}
frontend/choose-lang-content.php CHANGED
@@ -111,7 +111,7 @@ class PLL_Choose_Lang_Content extends PLL_Choose_lang {
111
  // http://wordpress.org/support/topic/search-for-empty-string-in-default-language
112
  if ( $this->options['hide_default'] && ! isset( $qv['lang'] ) && ( $is_archive || isset( $query->query['s'] ) || ( count( $query->query ) == 1 && ! empty( $qv['feed'] ) ) ) ) {
113
  $this->set_language( $this->model->get_language( $this->options['default_lang'] ) );
114
- $this->set_lang_query_var( $query, $this->curlang );
115
  }
116
  }
117
 
@@ -132,8 +132,8 @@ class PLL_Choose_Lang_Content extends PLL_Choose_lang {
132
  *
133
  * @since 0.9
134
  *
135
- * @param object|bool language found in get_language_from_content
136
- * @return object language
137
  */
138
  public function pll_get_current_language( $lang ) {
139
  return ! $lang ? $this->get_preferred_language() : $lang;
111
  // http://wordpress.org/support/topic/search-for-empty-string-in-default-language
112
  if ( $this->options['hide_default'] && ! isset( $qv['lang'] ) && ( $is_archive || isset( $query->query['s'] ) || ( count( $query->query ) == 1 && ! empty( $qv['feed'] ) ) ) ) {
113
  $this->set_language( $this->model->get_language( $this->options['default_lang'] ) );
114
+ $this->set_curlang_in_query( $query );
115
  }
116
  }
117
 
132
  *
133
  * @since 0.9
134
  *
135
+ * @param object|bool $lang Language found in get_language_from_content
136
+ * @return object Language
137
  */
138
  public function pll_get_current_language( $lang ) {
139
  return ! $lang ? $this->get_preferred_language() : $lang;
frontend/choose-lang-domain.php CHANGED
@@ -29,7 +29,7 @@ class PLL_Choose_Lang_Domain extends PLL_Choose_Lang_Url {
29
  * @since 1.5
30
  */
31
  public function home_requested() {
32
- $this->set_lang_query_var( $GLOBALS['wp_query'], $this->curlang );
33
  /** This action is documented in include/choose-lang.php */
34
  do_action( 'pll_home_requested' );
35
  }
29
  * @since 1.5
30
  */
31
  public function home_requested() {
32
+ $this->set_curlang_in_query( $GLOBALS['wp_query'] );
33
  /** This action is documented in include/choose-lang.php */
34
  do_action( 'pll_home_requested' );
35
  }
frontend/choose-lang.php CHANGED
@@ -98,7 +98,8 @@ abstract class PLL_Choose_Lang {
98
  $this->curlang->slug,
99
  time() + $expiration,
100
  COOKIEPATH,
101
- 2 == $this->options['force_lang'] ? parse_url( $this->links_model->home, PHP_URL_HOST ) : COOKIE_DOMAIN
 
102
  );
103
  }
104
  }
@@ -138,7 +139,7 @@ abstract class PLL_Choose_Lang {
138
  $temp = $v[ $j ];
139
  $v[ $j ] = $v[ $j + 1 ];
140
  $v[ $j + 1 ] = $temp;
141
- //swap keys
142
  $temp = $k[ $j ];
143
  $k[ $j ] = $k[ $j + 1 ];
144
  $k[ $j + 1 ] = $temp;
@@ -233,7 +234,7 @@ abstract class PLL_Choose_Lang {
233
  public function home_requested() {
234
  // we are already on the right page
235
  if ( $this->options['default_lang'] == $this->curlang->slug && $this->options['hide_default'] ) {
236
- $this->set_lang_query_var( $GLOBALS['wp_query'], $this->curlang );
237
 
238
  /**
239
  * Fires when the site root page is requested
@@ -299,7 +300,7 @@ abstract class PLL_Choose_Lang {
299
  */
300
  if ( $lang = apply_filters( 'pll_set_language_from_query', false, $query ) ) {
301
  $this->set_language( $lang );
302
- $this->set_lang_query_var( $query, $this->curlang );
303
  }
304
 
305
  // sets is_home on translated home page when it displays posts
@@ -314,18 +315,14 @@ abstract class PLL_Choose_Lang {
314
  }
315
 
316
  /**
317
- * sets the language in query
318
- * optimized for ( needs ) WP 3.5+
319
  *
320
- * @since 1.3
 
 
321
  */
322
- public function set_lang_query_var( &$query, $lang ) {
323
- // defining directly the tax_query ( rather than setting 'lang' avoids transforming the query by WP )
324
- $query->query_vars['tax_query'][] = array(
325
- 'taxonomy' => 'language',
326
- 'field' => 'term_taxonomy_id', // since WP 3.5
327
- 'terms' => $lang->term_taxonomy_id,
328
- 'operator' => 'IN',
329
- );
330
  }
331
  }
98
  $this->curlang->slug,
99
  time() + $expiration,
100
  COOKIEPATH,
101
+ 2 == $this->options['force_lang'] ? parse_url( $this->links_model->home, PHP_URL_HOST ) : COOKIE_DOMAIN,
102
+ is_ssl()
103
  );
104
  }
105
  }
139
  $temp = $v[ $j ];
140
  $v[ $j ] = $v[ $j + 1 ];
141
  $v[ $j + 1 ] = $temp;
142
+ // Swap keys
143
  $temp = $k[ $j ];
144
  $k[ $j ] = $k[ $j + 1 ];
145
  $k[ $j + 1 ] = $temp;
234
  public function home_requested() {
235
  // we are already on the right page
236
  if ( $this->options['default_lang'] == $this->curlang->slug && $this->options['hide_default'] ) {
237
+ $this->set_curlang_in_query( $GLOBALS['wp_query'] );
238
 
239
  /**
240
  * Fires when the site root page is requested
300
  */
301
  if ( $lang = apply_filters( 'pll_set_language_from_query', false, $query ) ) {
302
  $this->set_language( $lang );
303
+ $this->set_curlang_in_query( $query );
304
  }
305
 
306
  // sets is_home on translated home page when it displays posts
315
  }
316
 
317
  /**
318
+ * Sets the current language in the query
 
319
  *
320
+ * @since 2.2
321
+ *
322
+ * @param object $query
323
  */
324
+ protected function set_curlang_in_query( &$query ) {
325
+ $pll_query = new PLL_Query( $query, $this->model );
326
+ $pll_query->set_language( $this->curlang );
 
 
 
 
 
327
  }
328
  }
frontend/frontend-filters-links.php CHANGED
@@ -58,26 +58,7 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
58
  * @return string modified link
59
  */
60
  public function archive_link( $link ) {
61
- return $this->links_model->add_language_to_link( $link, $this->curlang );
62
- }
63
-
64
- /**
65
- * Modifies post & page links
66
- * and caches the result
67
- *
68
- * @since 0.7
69
- *
70
- * @param string $link post link
71
- * @param object $post post object
72
- * @return string modified post link
73
- */
74
- public function post_link( $link, $post ) {
75
- $cache_key = 'post:' . $post->ID;
76
- if ( false === $_link = $this->cache->get( $cache_key ) ) {
77
- $_link = parent::post_link( $link, $post );
78
- $this->cache->set( $cache_key, $_link );
79
- }
80
- return $_link;
81
  }
82
 
83
  /**
@@ -91,7 +72,8 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
91
  * @return string modified post link
92
  */
93
  public function _get_page_link( $link, $post_id ) {
94
- $cache_key = 'post:' . $post_id;
 
95
  if ( false === $_link = $this->cache->get( $cache_key ) ) {
96
  $_link = parent::_get_page_link( $link, $post_id );
97
  $this->cache->set( $cache_key, $_link );
@@ -129,7 +111,8 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
129
  * @return string modified post link
130
  */
131
  public function post_type_link( $link, $post ) {
132
- $cache_key = 'post:' . $post->ID;
 
133
  if ( false === $_link = $this->cache->get( $cache_key ) ) {
134
  $_link = parent::post_type_link( $link, $post );
135
  $this->cache->set( $cache_key, $_link );
@@ -152,7 +135,7 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
152
  $cache_key = 'term:' . $term->term_id;
153
  if ( false === $_link = $this->cache->get( $cache_key ) ) {
154
  if ( in_array( $tax, $this->model->get_filtered_taxonomies() ) ) {
155
- $_link = $this->links_model->add_language_to_link( $link, $this->curlang );
156
 
157
  /** This filter is documented in include/filters-links.php */
158
  $_link = apply_filters( 'pll_term_link', $_link, $this->curlang, $term );
@@ -217,7 +200,7 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
217
  $hreflangs = apply_filters( 'pll_rel_hreflang_attributes', $hreflangs );
218
 
219
  foreach ( $hreflangs as $lang => $url ) {
220
- printf( '<link rel="alternate" href="%s" hreflang="%s" />'."\n", esc_url( $url ), esc_attr( $lang ) );
221
  }
222
  }
223
  }
58
  * @return string modified link
59
  */
60
  public function archive_link( $link ) {
61
+ return $this->links_model->switch_language_in_link( $link, $this->curlang );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  }
63
 
64
  /**
72
  * @return string modified post link
73
  */
74
  public function _get_page_link( $link, $post_id ) {
75
+ $sample = false !== strpos( $link, '%pagename%' ); // To avoid a conflict with plugin Custom Permalinks
76
+ $cache_key = "post:{$post_id}:{$sample}";
77
  if ( false === $_link = $this->cache->get( $cache_key ) ) {
78
  $_link = parent::_get_page_link( $link, $post_id );
79
  $this->cache->set( $cache_key, $_link );
111
  * @return string modified post link
112
  */
113
  public function post_type_link( $link, $post ) {
114
+ $sample = false !== strpos( $link, '%postname%' ); // To avoid a conflict with plugin Custom Permalinks
115
+ $cache_key = "post:{$post->ID}:{$sample}";
116
  if ( false === $_link = $this->cache->get( $cache_key ) ) {
117
  $_link = parent::post_type_link( $link, $post );
118
  $this->cache->set( $cache_key, $_link );
135
  $cache_key = 'term:' . $term->term_id;
136
  if ( false === $_link = $this->cache->get( $cache_key ) ) {
137
  if ( in_array( $tax, $this->model->get_filtered_taxonomies() ) ) {
138
+ $_link = $this->links_model->switch_language_in_link( $link, $this->curlang );
139
 
140
  /** This filter is documented in include/filters-links.php */
141
  $_link = apply_filters( 'pll_term_link', $_link, $this->curlang, $term );
200
  $hreflangs = apply_filters( 'pll_rel_hreflang_attributes', $hreflangs );
201
 
202
  foreach ( $hreflangs as $lang => $url ) {
203
+ printf( '<link rel="alternate" href="%s" hreflang="%s" />' . "\n", esc_url( $url ), esc_attr( $lang ) );
204
  }
205
  }
206
  }
frontend/frontend-filters-search.php CHANGED
@@ -52,7 +52,7 @@ class PLL_Frontend_Filters_Search {
52
  $form = str_replace( $old, $new, $form );
53
  }
54
  else {
55
- $form = str_replace( '</form>', '<input type="hidden" name="lang" value="'.esc_attr( $this->curlang->slug ).'" /></form>', $form );
56
  }
57
  }
58
 
52
  $form = str_replace( $old, $new, $form );
53
  }
54
  else {
55
+ $form = str_replace( '</form>', '<input type="hidden" name="lang" value="' . esc_attr( $this->curlang->slug ) . '" /></form>', $form );
56
  }
57
  }
58
 
frontend/frontend-filters.php CHANGED
@@ -5,7 +5,7 @@
5
  *
6
  * @since 1.2
7
  */
8
- class PLL_Frontend_Filters extends PLL_Filters{
9
 
10
  /**
11
  * Constructor: setups filters and actions
@@ -93,15 +93,30 @@ class PLL_Frontend_Filters extends PLL_Filters{
93
  * @return array modified list of sticky posts ids
94
  */
95
  public function option_sticky_posts( $posts ) {
 
 
96
  if ( $this->curlang && ! empty( $posts ) ) {
97
- update_object_term_cache( $posts, 'post' ); // to avoid queries in foreach
98
- foreach ( $posts as $key => $post_id ) {
99
- $lang = $this->model->post->get_language( $post_id );
100
- if ( empty( $lang ) || $lang->term_id != $this->curlang->term_id ) {
101
- unset( $posts[ $key ] );
 
 
 
 
 
 
 
 
 
102
  }
 
103
  }
 
 
104
  }
 
105
  return $posts;
106
  }
107
 
@@ -291,7 +306,7 @@ class PLL_Frontend_Filters extends PLL_Filters{
291
  * @return null|string
292
  */
293
  public function get_user_metadata( $null, $id, $meta_key, $single ) {
294
- return 'description' === $meta_key && $this->curlang->slug !== $this->options['default_lang'] ? get_user_meta( $id, 'description_'.$this->curlang->slug, $single ) : $null;
295
  }
296
 
297
  /**
@@ -322,7 +337,6 @@ class PLL_Frontend_Filters extends PLL_Filters{
322
  *
323
  * @param int $post_id
324
  * @param object $post
325
- * @param bool $update Whether it is an update or not
326
  */
327
  public function save_post( $post_id, $post ) {
328
  if ( $this->model->is_translated_post_type( $post->post_type ) ) {
5
  *
6
  * @since 1.2
7
  */
8
+ class PLL_Frontend_Filters extends PLL_Filters {
9
 
10
  /**
11
  * Constructor: setups filters and actions
93
  * @return array modified list of sticky posts ids
94
  */
95
  public function option_sticky_posts( $posts ) {
96
+ global $wpdb;
97
+
98
  if ( $this->curlang && ! empty( $posts ) ) {
99
+ $_posts = wp_cache_get( 'sticky_posts', 'options' ); // This option is usually cached in 'all_options' by WP
100
+
101
+ if ( empty( $_posts ) || ! is_array( $_posts[ $this->curlang->term_taxonomy_id ] ) ) {
102
+ $posts = array_map( 'intval', $posts );
103
+ $posts = implode( ',', $posts );
104
+
105
+ $languages = $this->model->get_languages_list( array( 'fields' => 'term_taxonomy_id' ) );
106
+ $_posts = array_fill_keys( $languages, array() ); // Init with empty arrays
107
+ $languages = implode( ',', $languages );
108
+
109
+ $relations = $wpdb->get_results( "SELECT object_id, term_taxonomy_id FROM {$wpdb->term_relationships} WHERE object_id IN ({$posts}) AND term_taxonomy_id IN ({$languages})" );
110
+
111
+ foreach ( $relations as $relation ) {
112
+ $_posts[ $relation->term_taxonomy_id ][] = $relation->object_id;
113
  }
114
+ wp_cache_add( 'sticky_posts', $_posts, 'options' );
115
  }
116
+
117
+ $posts = $_posts[ $this->curlang->term_taxonomy_id ];
118
  }
119
+
120
  return $posts;
121
  }
122
 
306
  * @return null|string
307
  */
308
  public function get_user_metadata( $null, $id, $meta_key, $single ) {
309
+ return 'description' === $meta_key && $this->curlang->slug !== $this->options['default_lang'] ? get_user_meta( $id, 'description_' . $this->curlang->slug, $single ) : $null;
310
  }
311
 
312
  /**
337
  *
338
  * @param int $post_id
339
  * @param object $post
 
340
  */
341
  public function save_post( $post_id, $post ) {
342
  if ( $this->model->is_translated_post_type( $post->post_type ) ) {
frontend/frontend-links.php CHANGED
@@ -174,8 +174,8 @@ class PLL_Frontend_Links extends PLL_Links {
174
  *
175
  * @since 0.1
176
  *
177
- * @param object $language optional defaults to current language
178
- * @param bool $is_search optional wether we need the home url for a search form, defaults to false
179
  */
180
  public function get_home_url( $language = '', $is_search = false ) {
181
  if ( empty( $language ) ) {
174
  *
175
  * @since 0.1
176
  *
177
+ * @param object $language Optional, defaults to current language
178
+ * @param bool $is_search Optional, whether we need the home url for a search form, defaults to false
179
  */
180
  public function get_home_url( $language = '', $is_search = false ) {
181
  if ( empty( $language ) ) {
frontend/frontend-nav-menu.php CHANGED
@@ -12,6 +12,8 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
12
  * Constructor
13
  *
14
  * @since 1.2
 
 
15
  */
16
  public function __construct( &$polylang ) {
17
  parent::__construct( $polylang );
@@ -21,7 +23,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
21
  // Split the language switcher menu item in several language menu items
22
  add_filter( 'wp_get_nav_menu_items', array( $this, 'wp_get_nav_menu_items' ), 20 ); // after the customizer menus
23
  add_filter( 'wp_nav_menu_objects', array( $this, 'wp_nav_menu_objects' ) );
24
- add_filter( 'nav_menu_link_attributes', array( $this, 'nav_menu_link_attributes' ), 10, 3 );
25
 
26
  // Filters menus by language
27
  add_filter( 'theme_mod_nav_menu_locations', array( $this, 'nav_menu_locations' ), 20 );
@@ -78,7 +80,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
78
  // parent item for dropdown
79
  if ( ! empty( $options['dropdown'] ) ) {
80
  $item->title = $options['show_flags'] && $options['show_names'] ? $this->curlang->flag . '&nbsp;' . esc_html( $this->curlang->name ) : ( $options['show_flags'] ? $this->curlang->flag : esc_html( $this->curlang->name ) );
81
- $item->url = '';
82
  $item->classes = array( 'pll-parent-menu-item' );
83
  $new_items[] = $item;
84
  $offset++;
@@ -88,6 +90,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
88
  $lang_item = clone $item;
89
  $lang_item->ID = $lang_item->ID . '-' . $lang['slug']; // A unique ID
90
  $lang_item->title = $options['show_flags'] && $options['show_names'] ? $lang['flag'] . '<span style="margin-left:0.3em;">' . esc_html( $lang['name'] ) . '</span>' : ( $options['show_flags'] ? $lang['flag'] : esc_html( $lang['name'] ) );
 
91
  $lang_item->url = $lang['url'];
92
  $lang_item->lang = $lang['locale']; // Save this for use in nav_menu_link_attributes
93
  $lang_item->classes = $lang['classes'];
@@ -160,14 +163,15 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
160
 
161
  /**
162
  * Adds hreflang attribute for the language switcher menu items
163
- * available since WP3.6
164
  *
165
  * @since 1.1
166
  *
167
- * @param array $atts
 
168
  * @return array modified $atts
169
  */
170
- public function nav_menu_link_attributes( $atts, $item, $args ) {
171
  if ( isset( $item->lang ) ) {
172
  $atts['lang'] = $atts['hreflang'] = esc_attr( $item->lang );
173
  }
@@ -180,7 +184,7 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
180
  *
181
  * @since 1.2
182
  *
183
- * @param array|bool list of nav menus locations, false if menu locations have not been filled yet
184
  * @return array|bool modified list of nav menus locations
185
  */
186
  public function nav_menu_locations( $menus ) {
12
  * Constructor
13
  *
14
  * @since 1.2
15
+ *
16
+ * @param object $polylang
17
  */
18
  public function __construct( &$polylang ) {
19
  parent::__construct( $polylang );
23
  // Split the language switcher menu item in several language menu items
24
  add_filter( 'wp_get_nav_menu_items', array( $this, 'wp_get_nav_menu_items' ), 20 ); // after the customizer menus
25
  add_filter( 'wp_nav_menu_objects', array( $this, 'wp_nav_menu_objects' ) );
26
+ add_filter( 'nav_menu_link_attributes', array( $this, 'nav_menu_link_attributes' ), 10, 2 );
27
 
28
  // Filters menus by language
29
  add_filter( 'theme_mod_nav_menu_locations', array( $this, 'nav_menu_locations' ), 20 );
80
  // parent item for dropdown
81
  if ( ! empty( $options['dropdown'] ) ) {
82
  $item->title = $options['show_flags'] && $options['show_names'] ? $this->curlang->flag . '&nbsp;' . esc_html( $this->curlang->name ) : ( $options['show_flags'] ? $this->curlang->flag : esc_html( $this->curlang->name ) );
83
+ $item->attr_title = '';
84
  $item->classes = array( 'pll-parent-menu-item' );
85
  $new_items[] = $item;
86
  $offset++;
90
  $lang_item = clone $item;
91
  $lang_item->ID = $lang_item->ID . '-' . $lang['slug']; // A unique ID
92
  $lang_item->title = $options['show_flags'] && $options['show_names'] ? $lang['flag'] . '<span style="margin-left:0.3em;">' . esc_html( $lang['name'] ) . '</span>' : ( $options['show_flags'] ? $lang['flag'] : esc_html( $lang['name'] ) );
93
+ $lang_item->attr_title = '';
94
  $lang_item->url = $lang['url'];
95
  $lang_item->lang = $lang['locale']; // Save this for use in nav_menu_link_attributes
96
  $lang_item->classes = $lang['classes'];
163
 
164
  /**
165
  * Adds hreflang attribute for the language switcher menu items
166
+ * available since WP 3.6
167
  *
168
  * @since 1.1
169
  *
170
+ * @param array $atts
171
+ * @param object $item
172
  * @return array modified $atts
173
  */
174
+ public function nav_menu_link_attributes( $atts, $item ) {
175
  if ( isset( $item->lang ) ) {
176
  $atts['lang'] = $atts['hreflang'] = esc_attr( $item->lang );
177
  }
184
  *
185
  * @since 1.2
186
  *
187
+ * @param array|bool $menus list of nav menus locations, false if menu locations have not been filled yet
188
  * @return array|bool modified list of nav menus locations
189
  */
190
  public function nav_menu_locations( $menus ) {
frontend/frontend.php CHANGED
@@ -55,7 +55,11 @@ class PLL_Frontend extends PLL_Base {
55
  */
56
  public function init() {
57
  $this->links = new PLL_Frontend_Links( $this );
58
- $this->static_pages = new PLL_Frontend_Static_Pages( $this );
 
 
 
 
59
 
60
  // setup the language chooser
61
  $c = array( 'Content', 'Url', 'Url', 'Domain' );
@@ -79,7 +83,6 @@ class PLL_Frontend extends PLL_Base {
79
  $this->filters_search = new PLL_Frontend_Filters_Search( $this );
80
  }
81
 
82
-
83
  /**
84
  * when querying multiple taxonomies, makes sure that the language is not the queried object
85
  *
@@ -88,7 +91,8 @@ class PLL_Frontend extends PLL_Base {
88
  * @param object $query WP_Query object
89
  */
90
  public function parse_tax_query( $query ) {
91
- $queried_taxonomies = $this->get_queried_taxonomies( $query );
 
92
 
93
  if ( ! empty( $queried_taxonomies ) && 'language' == reset( $queried_taxonomies ) ) {
94
  $query->tax_query->queried_terms['language'] = array_shift( $query->tax_query->queried_terms );
@@ -104,31 +108,16 @@ class PLL_Frontend extends PLL_Base {
104
  */
105
  public function parse_query( $query ) {
106
  $qv = $query->query_vars;
107
- $taxonomies = $this->get_queried_taxonomies( $query );
108
-
109
- // to avoid returning an empty result if the query includes a translated taxonomy in a different language
110
- $has_tax = isset( $query->tax_query->queries ) && $this->model->have_translated_taxonomy( $query->tax_query->queries );
111
-
112
- // allow filtering recent posts and secondary queries by the current language
113
- // take care not to break queries for non visible post types such as nav_menu_items
114
- // do not filter if lang is set to an empty value
115
- // do not filter single page and translated taxonomies to avoid conflicts
116
- if ( ! empty( $this->curlang ) && ! isset( $qv['lang'] ) && ! $has_tax && empty( $qv['page_id'] ) && empty( $qv['pagename'] ) ) {
117
- if ( $taxonomies && ( empty( $qv['post_type'] ) || 'any' === $qv['post_type'] ) ) {
118
- foreach ( $taxonomies as $taxonomy ) {
119
- $tax_object = get_taxonomy( $taxonomy );
120
- if ( $this->model->is_translated_post_type( $tax_object->object_type ) ) {
121
- $this->choose_lang->set_lang_query_var( $query, $this->curlang );
122
- break;
123
- }
124
- }
125
- } elseif ( empty( $qv['post_type'] ) || $this->model->is_translated_post_type( $qv['post_type'] ) ) {
126
- $this->choose_lang->set_lang_query_var( $query, $this->curlang );
127
- }
128
  }
129
 
130
  // modifies query vars when the language is queried
131
- if ( ! empty( $qv['lang'] ) || ( ! empty( $taxonomies ) && array( 'language') == array_values( $taxonomies ) ) ) {
132
  // do we query a custom taxonomy?
133
  $taxonomies = array_diff( $taxonomies , array( 'language', 'category', 'post_tag' ) );
134
 
@@ -166,6 +155,9 @@ class PLL_Frontend extends PLL_Base {
166
  * overrides parent method
167
  *
168
  * @since 1.5.1
 
 
 
169
  */
170
  public function switch_blog( $new_blog, $old_blog ) {
171
  // need to check that some languages are defined when user is logged in, has several blogs, some without any languages
@@ -177,20 +169,12 @@ class PLL_Frontend extends PLL_Base {
177
 
178
  $lang = $this->model->get_language( $restore_curlang );
179
  $this->curlang = $lang ? $lang : $this->model->get_language( $this->options['default_lang'] );
180
- $this->static_pages->init();
 
 
 
 
181
  $this->load_strings_translations();
182
  }
183
  }
184
-
185
- /**
186
- * get queried taxonomies
187
- *
188
- * @since 1.8
189
- *
190
- * @param object $query WP_Query object
191
- * @return array queried taxonomies
192
- */
193
- protected function get_queried_taxonomies( $query ) {
194
- return isset( $query->tax_query->queried_terms ) ? array_keys( wp_list_filter( $query->tax_query->queried_terms, array( 'operator' => 'NOT IN' ), 'NOT' ) ) : array();
195
- }
196
  }
55
  */
56
  public function init() {
57
  $this->links = new PLL_Frontend_Links( $this );
58
+
59
+ // Static front page and page for posts
60
+ if ( 'page' === get_option( 'show_on_front' ) ) {
61
+ $this->static_pages = new PLL_Frontend_Static_Pages( $this );
62
+ }
63
 
64
  // setup the language chooser
65
  $c = array( 'Content', 'Url', 'Url', 'Domain' );
83
  $this->filters_search = new PLL_Frontend_Filters_Search( $this );
84
  }
85
 
 
86
  /**
87
  * when querying multiple taxonomies, makes sure that the language is not the queried object
88
  *
91
  * @param object $query WP_Query object
92
  */
93
  public function parse_tax_query( $query ) {
94
+ $pll_query = new PLL_Query( $query, $this->model );
95
+ $queried_taxonomies = $pll_query->get_queried_taxonomies();
96
 
97
  if ( ! empty( $queried_taxonomies ) && 'language' == reset( $queried_taxonomies ) ) {
98
  $query->tax_query->queried_terms['language'] = array_shift( $query->tax_query->queried_terms );
108
  */
109
  public function parse_query( $query ) {
110
  $qv = $query->query_vars;
111
+ $pll_query = new PLL_Query( $query, $this->model );
112
+ $taxonomies = $pll_query->get_queried_taxonomies();
113
+
114
+ // Allow filtering recent posts and secondary queries by the current language
115
+ if ( ! empty( $this->curlang ) ) {
116
+ $pll_query->filter_query( $this->curlang );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  }
118
 
119
  // modifies query vars when the language is queried
120
+ if ( ! empty( $qv['lang'] ) || ( ! empty( $taxonomies ) && array( 'language' ) == array_values( $taxonomies ) ) ) {
121
  // do we query a custom taxonomy?
122
  $taxonomies = array_diff( $taxonomies , array( 'language', 'category', 'post_tag' ) );
123
 
155
  * overrides parent method
156
  *
157
  * @since 1.5.1
158
+ *
159
+ * @param int $new_blog
160
+ * @param int $old_blog
161
  */
162
  public function switch_blog( $new_blog, $old_blog ) {
163
  // need to check that some languages are defined when user is logged in, has several blogs, some without any languages
169
 
170
  $lang = $this->model->get_language( $restore_curlang );
171
  $this->curlang = $lang ? $lang : $this->model->get_language( $this->options['default_lang'] );
172
+
173
+ if ( isset( $this->static_pages ) ) {
174
+ $this->static_pages->init();
175
+ }
176
+
177
  $this->load_strings_translations();
178
  }
179
  }
 
 
 
 
 
 
 
 
 
 
 
 
180
  }
include/api.php CHANGED
@@ -37,8 +37,8 @@ function pll_the_languages( $args = '' ) {
37
  *
38
  * @since 0.8.1
39
  *
40
- * @param string $field optional the language field to return 'name', 'locale', defaults to 'slug'
41
- * @return string|bool the requested field for the current language
42
  */
43
  function pll_current_language( $field = 'slug' ) {
44
  return isset( PLL()->curlang->$field ) ? PLL()->curlang->$field : false;
@@ -49,8 +49,8 @@ function pll_current_language( $field = 'slug' ) {
49
  *
50
  * @since 1.0
51
  *
52
- * @param string $field optional the language field to return 'name', 'locale', defaults to 'slug'
53
- * @return string the requested field for the default language
54
  */
55
  function pll_default_language( $field = 'slug' ) {
56
  return isset( PLL()->options['default_lang'] ) && ( $lang = PLL()->model->get_language( PLL()->options['default_lang'] ) ) && isset( $lang->$field ) ? $lang->$field : false;
@@ -143,7 +143,7 @@ function pll_esc_html__( $string ) {
143
  *
144
  * @since 2.1
145
  *
146
- * @param $string
147
  * @return string
148
  */
149
  function pll_esc_attr__( $string ) {
@@ -155,7 +155,7 @@ function pll_esc_attr__( $string ) {
155
  *
156
  * @since 0.6
157
  *
158
- * @param string $string the string to translate
159
  */
160
  function pll_e( $string ) {
161
  echo pll__( $string );
@@ -166,7 +166,7 @@ function pll_e( $string ) {
166
  *
167
  * @since 2.1
168
  *
169
- * @param string $string the string to translate
170
  */
171
  function pll_esc_html_e( $string ) {
172
  echo pll_esc_html__( $string );
@@ -177,7 +177,7 @@ function pll_esc_html_e( $string ) {
177
  *
178
  * @since 2.1
179
  *
180
- * @param $string
181
  */
182
  function pll_esc_attr_e( $string ) {
183
  echo pll_esc_attr__( $string );
@@ -221,7 +221,7 @@ function pll_translate_string( $string, $lang ) {
221
  *
222
  * @since 1.0.1
223
  *
224
- * @param string post type name
225
  * @return bool
226
  */
227
  function pll_is_translated_post_type( $post_type ) {
@@ -233,7 +233,7 @@ function pll_is_translated_post_type( $post_type ) {
233
  *
234
  * @since 1.0.1
235
  *
236
- * @param string taxonomy name
237
  * @return bool
238
  */
239
  function pll_is_translated_taxonomy( $tax ) {
@@ -310,8 +310,8 @@ function pll_save_term_translations( $arr ) {
310
  * @since 1.5.4
311
  *
312
  * @param int $post_id
313
- * @param string $field optional the language field to return 'name', 'locale', defaults to 'slug'
314
- * @return bool|string the requested field for the post language, false if no language is associated to that post
315
  */
316
  function pll_get_post_language( $post_id, $field = 'slug' ) {
317
  return ( $lang = PLL()->model->post->get_language( $post_id ) ) ? $lang->$field : false;
@@ -323,8 +323,8 @@ function pll_get_post_language( $post_id, $field = 'slug' ) {
323
  * @since 1.5.4
324
  *
325
  * @param int $term_id
326
- * @param string $field optional the language field to return 'name', 'locale', defaults to 'slug'
327
- * @return bool|string the requested field for the term language, false if no language is associated to that term
328
  */
329
  function pll_get_term_language( $term_id, $field = 'slug' ) {
330
  return ( $lang = PLL()->model->term->get_language( $term_id ) ) ? $lang->$field : false;
37
  *
38
  * @since 0.8.1
39
  *
40
+ * @param string $field Optional, the language field to return ( see PLL_Language ), defaults to 'slug'
41
+ * @return string|bool The requested field for the current language
42
  */
43
  function pll_current_language( $field = 'slug' ) {
44
  return isset( PLL()->curlang->$field ) ? PLL()->curlang->$field : false;
49
  *
50
  * @since 1.0
51
  *
52
+ * @param string $field Optional, the language field to return ( see PLL_Language ), defaults to 'slug'
53
+ * @return string The requested field for the default language
54
  */
55
  function pll_default_language( $field = 'slug' ) {
56
  return isset( PLL()->options['default_lang'] ) && ( $lang = PLL()->model->get_language( PLL()->options['default_lang'] ) ) && isset( $lang->$field ) ? $lang->$field : false;
143
  *
144
  * @since 2.1
145
  *
146
+ * @param string $string The string to translate
147
  * @return string
148
  */
149
  function pll_esc_attr__( $string ) {
155
  *
156
  * @since 0.6
157
  *
158
+ * @param string $string The string to translate
159
  */
160
  function pll_e( $string ) {
161
  echo pll__( $string );
166
  *
167
  * @since 2.1
168
  *
169
+ * @param string $string The string to translate
170
  */
171
  function pll_esc_html_e( $string ) {
172
  echo pll_esc_html__( $string );
177
  *
178
  * @since 2.1
179
  *
180
+ * @param string $string The string to translate
181
  */
182
  function pll_esc_attr_e( $string ) {
183
  echo pll_esc_attr__( $string );
221
  *
222
  * @since 1.0.1
223
  *
224
+ * @param string $post_type Post type name
225
  * @return bool
226
  */
227
  function pll_is_translated_post_type( $post_type ) {
233
  *
234
  * @since 1.0.1
235
  *
236
+ * @param string $tax Taxonomy name
237
  * @return bool
238
  */
239
  function pll_is_translated_taxonomy( $tax ) {
310
  * @since 1.5.4
311
  *
312
  * @param int $post_id
313
+ * @param string $field Optional, the language field to return ( see PLL_Language ), defaults to 'slug'
314
+ * @return bool|string The requested field for the post language, false if no language is associated to that post
315
  */
316
  function pll_get_post_language( $post_id, $field = 'slug' ) {
317
  return ( $lang = PLL()->model->post->get_language( $post_id ) ) ? $lang->$field : false;
323
  * @since 1.5.4
324
  *
325
  * @param int $term_id
326
+ * @param string $field Optional, the language field to return ( see PLL_Language ), defaults to 'slug'
327
+ * @return bool|string The requested field for the term language, false if no language is associated to that term
328
  */
329
  function pll_get_term_language( $term_id, $field = 'slug' ) {
330
  return ( $lang = PLL()->model->term->get_language( $term_id ) ) ? $lang->$field : false;
include/base.php CHANGED
@@ -77,6 +77,8 @@ abstract class PLL_Base {
77
  *
78
  * @since 1.5.1
79
  *
 
 
80
  * @return bool not used by WP but by child class
81
  */
82
  public function switch_blog( $new_blog, $old_blog ) {
77
  *
78
  * @since 1.5.1
79
  *
80
+ * @param int $new_blog
81
+ * @param int $old_blog
82
  * @return bool not used by WP but by child class
83
  */
84
  public function switch_blog( $new_blog, $old_blog ) {
include/cache.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /**
4
- * an extremely simple non persistent cache system
5
  * not as fast as using directly an array but more readable
6
  *
7
  * @since 1.7
@@ -10,7 +10,7 @@ class PLL_Cache {
10
  protected $blog_id, $cache;
11
 
12
  /**
13
- * constructor
14
  *
15
  * @since 1.7
16
  */
@@ -20,7 +20,7 @@ class PLL_Cache {
20
  }
21
 
22
  /**
23
- * called when switching blog
24
  *
25
  * @since 1.7
26
  *
@@ -31,19 +31,19 @@ class PLL_Cache {
31
  }
32
 
33
  /**
34
- * add a value in cache
35
  *
36
  * @since 1.7
37
  *
38
  * @param string $key
39
- * @param mixed $data
40
  */
41
  public function set( $key, $data ) {
42
  $this->cache[ $this->blog_id ][ $key ] = $data;
43
  }
44
 
45
  /**
46
- * get value from cache
47
  *
48
  * @since 1.7
49
  *
@@ -55,9 +55,11 @@ class PLL_Cache {
55
  }
56
 
57
  /**
58
- * clean the cache (for this blog only)
59
  *
60
  * @since 1.7
 
 
61
  */
62
  public function clean( $key = '' ) {
63
  if ( empty( $key ) ) {
1
  <?php
2
 
3
  /**
4
+ * An extremely simple non persistent cache system
5
  * not as fast as using directly an array but more readable
6
  *
7
  * @since 1.7
10
  protected $blog_id, $cache;
11
 
12
  /**
13
+ * Constructor
14
  *
15
  * @since 1.7
16
  */
20
  }
21
 
22
  /**
23
+ * Called when switching blog
24
  *
25
  * @since 1.7
26
  *
31
  }
32
 
33
  /**
34
+ * Add a value in cache
35
  *
36
  * @since 1.7
37
  *
38
  * @param string $key
39
+ * @param mixed $data
40
  */
41
  public function set( $key, $data ) {
42
  $this->cache[ $this->blog_id ][ $key ] = $data;
43
  }
44
 
45
  /**
46
+ * Get value from cache
47
  *
48
  * @since 1.7
49
  *
55
  }
56
 
57
  /**
58
+ * Clean the cache (for this blog only)
59
  *
60
  * @since 1.7
61
+ *
62
+ * @param string $key
63
  */
64
  public function clean( $key = '' ) {
65
  if ( empty( $key ) ) {
include/class-polylang.php CHANGED
@@ -1,74 +1,74 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // don't access directly
5
  };
6
 
7
- // default directory to store user data such as custom flags
8
  if ( ! defined( 'PLL_LOCAL_DIR' ) ) {
9
  define( 'PLL_LOCAL_DIR', WP_CONTENT_DIR . '/polylang' );
10
  }
11
 
12
- // includes local config file if exists
13
  if ( file_exists( PLL_LOCAL_DIR . '/pll-config.php' ) ) {
14
  include_once PLL_LOCAL_DIR . '/pll-config.php';
15
  }
16
 
17
  /**
18
- * controls the plugin, as well as activation, and deactivation
19
  *
20
  * @since 0.1
21
  */
22
  class Polylang {
23
 
24
  /**
25
- * constructor
26
  *
27
  * @since 0.1
28
  */
29
  public function __construct() {
30
- require_once PLL_INC . '/functions-wpcom-vip.php'; // VIP functions
31
- spl_autoload_register( array( $this, 'autoload' ) ); // autoload classes
32
 
33
  $install = new PLL_Install( POLYLANG_BASENAME );
34
 
35
- // stopping here if we are going to deactivate the plugin ( avoids breaking rewrite rules )
36
  if ( $install->is_deactivation() ) {
37
  return;
38
  }
39
 
40
- // plugin initialization
41
- // take no action before all plugins are loaded
42
  add_action( 'plugins_loaded', array( $this, 'init' ), 1 );
43
 
44
- // override load text domain waiting for the language to be defined
45
- // here for plugins which load text domain as soon as loaded :(
46
  if ( ! defined( 'PLL_OLT' ) || PLL_OLT ) {
47
  PLL_OLT_Manager::instance();
48
  }
49
 
50
- // extra code for compatibility with some plugins
51
- // loaded as soon as possible as we may need to act before other plugins are loaded
52
  if ( ! defined( 'PLL_PLUGINS_COMPAT' ) || PLL_PLUGINS_COMPAT ) {
53
  PLL_Plugins_Compat::instance();
54
  }
55
  }
56
 
57
  /**
58
- * autoload classes
59
  *
60
  * @since 1.2
61
  *
62
  * @param string $class
63
  */
64
  public function autoload( $class ) {
65
- // not a Polylang class
66
  if ( 0 !== strncmp( 'PLL_', $class, 4 ) ) {
67
  return;
68
  }
69
 
70
  $class = str_replace( '_', '-', strtolower( substr( $class, 4 ) ) );
71
- $to_find = array( 'media', 'share', 'slug', 'slugs', 'sync', 'translate', 'wpml', 'xdata' );
72
  $dir = implode( '-', array_intersect( explode( '-', $class ), $to_find ) );
73
 
74
  $dirs = array(
@@ -91,31 +91,42 @@ class Polylang {
91
  }
92
 
93
  /**
94
- * defines constants
95
- * may be overriden by a plugin if set before plugins_loaded, 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  *
97
  * @since 1.6
98
  */
99
  static public function define_constants() {
100
- // cookie name. no cookie will be used if set to false
101
  if ( ! defined( 'PLL_COOKIE' ) ) {
102
  define( 'PLL_COOKIE', 'pll_language' );
103
  }
104
 
105
- // avoid loading polylang admin for frontend ajax requests
106
- // special test for plupload which does not use jquery ajax and thus does not pass our ajax prefilter
107
- // special test for customize_save done in frontend but for which we want to load the admin
108
  if ( ! defined( 'PLL_AJAX_ON_FRONT' ) ) {
109
- $in = isset( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], array( 'upload-attachment', 'customize_save' ) );
110
- define( 'PLL_AJAX_ON_FRONT', defined( 'DOING_AJAX' ) && DOING_AJAX && empty( $_REQUEST['pll_ajax_backend'] ) && ! $in );
111
  }
112
 
113
- // admin
114
  if ( ! defined( 'PLL_ADMIN' ) ) {
115
  define( 'PLL_ADMIN', defined( 'DOING_CRON' ) || ( is_admin() && ! PLL_AJAX_ON_FRONT ) );
116
  }
117
 
118
- // settings page whatever the tab
119
  if ( ! defined( 'PLL_SETTINGS' ) ) {
120
  define( 'PLL_SETTINGS', is_admin() && ( ( isset( $_GET['page'] ) && 0 === strpos( $_GET['page'], 'mlang' ) ) || ! empty( $_REQUEST['pll_ajax_settings'] ) ) );
121
  }
@@ -133,16 +144,16 @@ class Polylang {
133
  self::define_constants();
134
  $options = get_option( 'polylang' );
135
 
136
- // plugin upgrade
137
  if ( $options && version_compare( $options['version'], POLYLANG_VERSION, '<' ) ) {
138
  $upgrade = new PLL_Upgrade( $options );
139
- if ( ! $upgrade->upgrade() ) { // if the version is too old
140
  return;
141
  }
142
  }
143
 
144
  // Make sure that this filter is *always* added before PLL_Model::get_languages_list() is called for the first time
145
- add_filter( 'pll_languages_list', array( 'PLL_Static_Pages', 'pll_languages_list' ), 2, 2 ); // before PLL_Links_Model
146
 
147
  /**
148
  * Filter the model class to use
@@ -162,7 +173,7 @@ class Polylang {
162
  elseif ( PLL_ADMIN ) {
163
  $polylang = new PLL_Admin( $links_model );
164
  }
165
- // do nothing on frontend if no language is defined
166
  elseif ( $model->get_languages_list() && empty( $_GET['deactivate-polylang'] ) ) {
167
  $polylang = new PLL_Frontend( $links_model );
168
  }
@@ -187,7 +198,7 @@ class Polylang {
187
  */
188
  do_action_ref_array( 'pll_pre_init', array( &$polylang ) );
189
 
190
- require_once PLL_INC.'/api.php'; // loads the API
191
 
192
  if ( ! defined( 'PLL_WPML_COMPAT' ) || PLL_WPML_COMPAT ) {
193
  PLL_WPML_Compat::instance(); // WPML API
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Don't access directly
5
  };
6
 
7
+ // Default directory to store user data such as custom flags
8
  if ( ! defined( 'PLL_LOCAL_DIR' ) ) {
9
  define( 'PLL_LOCAL_DIR', WP_CONTENT_DIR . '/polylang' );
10
  }
11
 
12
+ // Includes local config file if exists
13
  if ( file_exists( PLL_LOCAL_DIR . '/pll-config.php' ) ) {
14
  include_once PLL_LOCAL_DIR . '/pll-config.php';
15
  }
16
 
17
  /**
18
+ * Controls the plugin, as well as activation, and deactivation
19
  *
20
  * @since 0.1
21
  */
22
  class Polylang {
23
 
24
  /**
25
+ * Constructor
26
  *
27
  * @since 0.1
28
  */
29
  public function __construct() {
30
+ require_once PLL_INC . '/functions.php'; // VIP functions
31
+ spl_autoload_register( array( $this, 'autoload' ) ); // Autoload classes
32
 
33
  $install = new PLL_Install( POLYLANG_BASENAME );
34
 
35
+ // Stopping here if we are going to deactivate the plugin ( avoids breaking rewrite rules )
36
  if ( $install->is_deactivation() ) {
37
  return;
38
  }
39
 
40
+ // Plugin initialization
41
+ // Take no action before all plugins are loaded
42
  add_action( 'plugins_loaded', array( $this, 'init' ), 1 );
43
 
44
+ // Override load text domain waiting for the language to be defined
45
+ // Here for plugins which load text domain as soon as loaded :(
46
  if ( ! defined( 'PLL_OLT' ) || PLL_OLT ) {
47
  PLL_OLT_Manager::instance();
48
  }
49
 
50
+ // Extra code for compatibility with some plugins
51
+ // Loaded as soon as possible as we may need to act before other plugins are loaded
52
  if ( ! defined( 'PLL_PLUGINS_COMPAT' ) || PLL_PLUGINS_COMPAT ) {
53
  PLL_Plugins_Compat::instance();
54
  }
55
  }
56
 
57
  /**
58
+ * Autoload classes
59
  *
60
  * @since 1.2
61
  *
62
  * @param string $class
63
  */
64
  public function autoload( $class ) {
65
+ // Not a Polylang class
66
  if ( 0 !== strncmp( 'PLL_', $class, 4 ) ) {
67
  return;
68
  }
69
 
70
  $class = str_replace( '_', '-', strtolower( substr( $class, 4 ) ) );
71
+ $to_find = array( 'media', 'share', 'slug', 'slugs', 'sync', 'translate', 'wpml', 'xdata', 'rest' );
72
  $dir = implode( '-', array_intersect( explode( '-', $class ), $to_find ) );
73
 
74
  $dirs = array(
91
  }
92
 
93
  /**
94
+ * Tells whether the current request is an ajax request on frontend or not
95
+ *
96
+ * @since 2.2
97
+ *
98
+ * @return bool
99
+ */
100
+ static public function is_ajax_on_front() {
101
+ // Special test for plupload which does not use jquery ajax and thus does not pass our ajax prefilter
102
+ // Special test for customize_save done in frontend but for which we want to load the admin
103
+ $in = isset( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], array( 'upload-attachment', 'customize_save' ) );
104
+ return wp_doing_ajax() && empty( $_REQUEST['pll_ajax_backend'] ) && ! $in;
105
+ }
106
+
107
+ /**
108
+ * Defines constants
109
+ * May be overriden by a plugin if set before plugins_loaded, 1
110
  *
111
  * @since 1.6
112
  */
113
  static public function define_constants() {
114
+ // Cookie name. no cookie will be used if set to false
115
  if ( ! defined( 'PLL_COOKIE' ) ) {
116
  define( 'PLL_COOKIE', 'pll_language' );
117
  }
118
 
119
+ // Avoid loading polylang admin for frontend ajax requests
 
 
120
  if ( ! defined( 'PLL_AJAX_ON_FRONT' ) ) {
121
+ define( 'PLL_AJAX_ON_FRONT', self::is_ajax_on_front() );
 
122
  }
123
 
124
+ // Admin
125
  if ( ! defined( 'PLL_ADMIN' ) ) {
126
  define( 'PLL_ADMIN', defined( 'DOING_CRON' ) || ( is_admin() && ! PLL_AJAX_ON_FRONT ) );
127
  }
128
 
129
+ // Settings page whatever the tab
130
  if ( ! defined( 'PLL_SETTINGS' ) ) {
131
  define( 'PLL_SETTINGS', is_admin() && ( ( isset( $_GET['page'] ) && 0 === strpos( $_GET['page'], 'mlang' ) ) || ! empty( $_REQUEST['pll_ajax_settings'] ) ) );
132
  }
144
  self::define_constants();
145
  $options = get_option( 'polylang' );
146
 
147
+ // Plugin upgrade
148
  if ( $options && version_compare( $options['version'], POLYLANG_VERSION, '<' ) ) {
149
  $upgrade = new PLL_Upgrade( $options );
150
+ if ( ! $upgrade->upgrade() ) { // If the version is too old
151
  return;
152
  }
153
  }
154
 
155
  // Make sure that this filter is *always* added before PLL_Model::get_languages_list() is called for the first time
156
+ add_filter( 'pll_languages_list', array( 'PLL_Static_Pages', 'pll_languages_list' ), 2, 2 ); // Before PLL_Links_Model
157
 
158
  /**
159
  * Filter the model class to use
173
  elseif ( PLL_ADMIN ) {
174
  $polylang = new PLL_Admin( $links_model );
175
  }
176
+ // Do nothing on frontend if no language is defined
177
  elseif ( $model->get_languages_list() && empty( $_GET['deactivate-polylang'] ) ) {
178
  $polylang = new PLL_Frontend( $links_model );
179
  }
198
  */
199
  do_action_ref_array( 'pll_pre_init', array( &$polylang ) );
200
 
201
+ require_once PLL_INC . '/api.php'; // Loads the API
202
 
203
  if ( ! defined( 'PLL_WPML_COMPAT' ) || PLL_WPML_COMPAT ) {
204
  PLL_WPML_Compat::instance(); // WPML API
include/filters-links.php CHANGED
@@ -54,7 +54,7 @@ class PLL_Filters_Links {
54
  */
55
  public function _get_page_link( $link, $post_id ) {
56
  // /!\ WP does not use pretty permalinks for preview
57
- return false !== strpos( $link, 'preview=true' ) && false !== strpos( $link, 'page_id=' ) ? $link : $this->links_model->add_language_to_link( $link, $this->model->post->get_language( $post_id ) );
58
  }
59
 
60
  /**
@@ -67,7 +67,7 @@ class PLL_Filters_Links {
67
  * @return string modified attachment link
68
  */
69
  public function attachment_link( $link, $post_id ) {
70
- return wp_get_post_parent_id( $post_id ) ? $link : $this->links_model->add_language_to_link( $link, $this->model->post->get_language( $post_id ) );
71
  }
72
 
73
  /**
@@ -83,7 +83,7 @@ class PLL_Filters_Links {
83
  // /!\ WP does not use pretty permalinks for preview
84
  if ( ( false === strpos( $link, 'preview=true' ) || false === strpos( $link, 'p=' ) ) && $this->model->is_translated_post_type( $post->post_type ) ) {
85
  $lang = $this->model->post->get_language( $post->ID );
86
- $link = $this->options['force_lang'] ? $this->links_model->add_language_to_link( $link, $lang ) : $link;
87
 
88
  /**
89
  * Filter a post or custom post type link
@@ -113,7 +113,7 @@ class PLL_Filters_Links {
113
  public function term_link( $link, $term, $tax ) {
114
  if ( $this->model->is_translated_taxonomy( $tax ) ) {
115
  $lang = $this->model->term->get_language( $term->term_id );
116
- $link = $this->options['force_lang'] ? $this->links_model->add_language_to_link( $link, $lang ) : $link;
117
 
118
  /**
119
  * Filter a term link
@@ -161,7 +161,7 @@ class PLL_Filters_Links {
161
  * @return string modified link
162
  */
163
  public function post_type_archive_link( $link, $post_type ) {
164
- return $this->model->is_translated_post_type( $post_type ) && 'post' !== $post_type ? $this->links_model->add_language_to_link( $link, $this->curlang ) : $link;
165
  }
166
  }
167
 
54
  */
55
  public function _get_page_link( $link, $post_id ) {
56
  // /!\ WP does not use pretty permalinks for preview
57
+ return false !== strpos( $link, 'preview=true' ) && false !== strpos( $link, 'page_id=' ) ? $link : $this->links_model->switch_language_in_link( $link, $this->model->post->get_language( $post_id ) );
58
  }
59
 
60
  /**
67
  * @return string modified attachment link
68
  */
69
  public function attachment_link( $link, $post_id ) {
70
+ return wp_get_post_parent_id( $post_id ) ? $link : $this->links_model->switch_language_in_link( $link, $this->model->post->get_language( $post_id ) );
71
  }
72
 
73
  /**
83
  // /!\ WP does not use pretty permalinks for preview
84
  if ( ( false === strpos( $link, 'preview=true' ) || false === strpos( $link, 'p=' ) ) && $this->model->is_translated_post_type( $post->post_type ) ) {
85
  $lang = $this->model->post->get_language( $post->ID );
86
+ $link = $this->options['force_lang'] ? $this->links_model->switch_language_in_link( $link, $lang ) : $link;
87
 
88
  /**
89
  * Filter a post or custom post type link
113
  public function term_link( $link, $term, $tax ) {
114
  if ( $this->model->is_translated_taxonomy( $tax ) ) {
115
  $lang = $this->model->term->get_language( $term->term_id );
116
+ $link = $this->options['force_lang'] ? $this->links_model->switch_language_in_link( $link, $lang ) : $link;
117
 
118
  /**
119
  * Filter a term link
161
  * @return string modified link
162
  */
163
  public function post_type_archive_link( $link, $post_type ) {
164
+ return $this->model->is_translated_post_type( $post_type ) && 'post' !== $post_type ? $this->links_model->switch_language_in_link( $link, $this->curlang ) : $link;
165
  }
166
  }
167
 
include/filters.php CHANGED
@@ -138,12 +138,14 @@ class PLL_Filters {
138
  'nopaging' => true,
139
  'post_type' => $args['post_type'],
140
  'fields' => 'ids',
141
- 'tax_query' => array( array(
142
- 'taxonomy' => 'language',
143
- 'field' => 'term_taxonomy_id', // Since WP 3.5
144
- 'terms' => $language->term_taxonomy_id,
145
- 'operator' => 'NOT IN',
146
- ) ),
 
 
147
  );
148
 
149
  $args['exclude'] = array_merge( $args['exclude'], get_posts( $r ) );
138
  'nopaging' => true,
139
  'post_type' => $args['post_type'],
140
  'fields' => 'ids',
141
+ 'tax_query' => array(
142
+ array(
143
+ 'taxonomy' => 'language',
144
+ 'field' => 'term_taxonomy_id', // Since WP 3.5
145
+ 'terms' => $language->term_taxonomy_id,
146
+ 'operator' => 'NOT IN',
147
+ ),
148
+ ),
149
  );
150
 
151
  $args['exclude'] = array_merge( $args['exclude'], get_posts( $r ) );
include/functions-wpcom-vip.php DELETED
@@ -1,29 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Define wordpress.com VIP equivalent of uncached functions
5
- */
6
-
7
- if ( ! function_exists( 'wpcom_vip_get_page_by_title' ) ) {
8
- function wpcom_vip_get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) {
9
- return get_page_by_title( $page_title, $output, $post_type );
10
- }
11
- }
12
-
13
- if ( ! function_exists( 'wpcom_vip_get_category_by_slug' ) ) {
14
- function wpcom_vip_get_category_by_slug( $slug ) {
15
- return get_category_by_slug( $slug );
16
- }
17
- }
18
-
19
- if ( ! function_exists( 'wpcom_vip_get_term_by' ) ) {
20
- function wpcom_vip_get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
21
- return get_term_by( $field, $value, $taxonomy, $output, $filter );
22
- }
23
- }
24
-
25
- if ( ! function_exists( 'wpcom_vip_get_term_link' ) ) {
26
- function wpcom_vip_get_term_link( $term, $taxonomy = '' ) {
27
- return get_term_link( $term, $taxonomy );
28
- }
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
include/functions.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
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' ) ) {
9
+ /**
10
+ * Retrieve a page given its title.
11
+ *
12
+ * @since 2.0
13
+ *
14
+ * @param string $page_title Page title
15
+ * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N. Default OBJECT
16
+ * @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
17
+ * @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
18
+ */
19
+ function wpcom_vip_get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) {
20
+ return get_page_by_title( $page_title, $output, $post_type );
21
+ }
22
+ }
23
+
24
+ if ( ! function_exists( 'wpcom_vip_get_category_by_slug' ) ) {
25
+ /**
26
+ * Retrieve category object by category slug.
27
+ *
28
+ * @since 2.0
29
+ *
30
+ * @param string $slug The category slug.
31
+ * @return object Category data object
32
+ */
33
+ function wpcom_vip_get_category_by_slug( $slug ) {
34
+ return get_category_by_slug( $slug );
35
+ }
36
+ }
37
+
38
+ if ( ! function_exists( 'wpcom_vip_get_term_by' ) ) {
39
+ /**
40
+ * Get all Term data from database by Term field and data.
41
+ *
42
+ * @since 2.0
43
+ *
44
+ * @param string $field Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id'
45
+ * @param string|int $value Search for this term value
46
+ * @param string $taxonomy Taxonomy name. Optional, if `$field` is 'term_taxonomy_id'.
47
+ * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N. Default OBJECT.
48
+ * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
49
+ * @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.
50
+ */
51
+ function wpcom_vip_get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
52
+ return get_term_by( $field, $value, $taxonomy, $output, $filter );
53
+ }
54
+ }
55
+
56
+ if ( ! function_exists( 'wpcom_vip_get_term_link' ) ) {
57
+ /**
58
+ * Generate a permalink for a taxonomy term archive.
59
+ *
60
+ * @since 2.0
61
+ *
62
+ * @param object|int|string $term The term object, ID, or slug whose link will be retrieved.
63
+ * @param string $taxonomy Optional. Taxonomy. Default empty.
64
+ * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist.
65
+ */
66
+ function wpcom_vip_get_term_link( $term, $taxonomy = '' ) {
67
+ return get_term_link( $term, $taxonomy );
68
+ }
69
+ }
70
+
71
+ if ( ! function_exists( 'wp_doing_ajax' ) ) {
72
+ /**
73
+ * Determines whether the current request is a WordPress Ajax request.
74
+ * Backward compatibility function for WP < 4.7
75
+ *
76
+ * @since 2.2
77
+ *
78
+ * @return bool True if it's a WordPress Ajax request, false otherwise.
79
+ */
80
+ function wp_doing_ajax() {
81
+ /** This filter is documented in wp-includes/load.php */
82
+ return apply_filters( 'wp_doing_ajax', defined( 'DOING_AJAX' ) && DOING_AJAX );
83
+ }
84
+ }
include/language.php CHANGED
@@ -47,8 +47,8 @@ class PLL_Language {
47
  *
48
  * @since 1.2
49
  *
50
- * @param object|array $language 'language' term or language object properties stored as an array
51
- * @param object $term_language corresponding 'term_language' term
52
  */
53
  public function __construct( $language, $term_language = null ) {
54
  // build the object from all properties stored as an array
@@ -194,7 +194,7 @@ class PLL_Language {
194
 
195
  /**
196
  * set home_url scheme
197
- * this can't be cached accross pages
198
  *
199
  * @since 1.6.4
200
  */
@@ -236,7 +236,7 @@ class PLL_Language {
236
  'roh' => 'rm',
237
  'srd' => 'sc',
238
  'tuk' => 'tk',
239
- );
240
  $locale = isset( $valid_locales[ $this->locale ] ) ? $valid_locales[ $this->locale ] : $this->locale;
241
  return str_replace( '_', '-', $locale );
242
  }
47
  *
48
  * @since 1.2
49
  *
50
+ * @param object|array $language 'language' term or language object properties stored as an array
51
+ * @param object $term_language Corresponding 'term_language' term
52
  */
53
  public function __construct( $language, $term_language = null ) {
54
  // build the object from all properties stored as an array
194
 
195
  /**
196
  * set home_url scheme
197
+ * this can't be cached across pages
198
  *
199
  * @since 1.6.4
200
  */
236
  'roh' => 'rm',
237
  'srd' => 'sc',
238
  'tuk' => 'tk',
239
+ );
240
  $locale = isset( $valid_locales[ $this->locale ] ) ? $valid_locales[ $this->locale ] : $this->locale;
241
  return str_replace( '_', '-', $locale );
242
  }
include/license.php CHANGED
@@ -30,7 +30,7 @@ class PLL_License {
30
  $this->api_url = empty( $api_url ) ? $this->api_url : $api_url;
31
 
32
  $licenses = get_option( 'polylang_licenses' );
33
- $this->license_key = empty( $licenses[ $this->id ]['key'] ) ? '' : $licenses[ $this->id ]['key'];
34
  if ( ! empty( $licenses[ $this->id ]['data'] ) ) {
35
  $this->license_data = $licenses[ $this->id ]['data'];
36
  }
30
  $this->api_url = empty( $api_url ) ? $this->api_url : $api_url;
31
 
32
  $licenses = get_option( 'polylang_licenses' );
33
+ $this->license_key = empty( $licenses[ $this->id ]['key'] ) ? '' : $licenses[ $this->id ]['key'];
34
  if ( ! empty( $licenses[ $this->id ]['data'] ) ) {
35
  $this->license_data = $licenses[ $this->id ]['data'];
36
  }
include/links-abstract-domain.php CHANGED
@@ -24,6 +24,18 @@ abstract class PLL_Links_Abstract_Domain extends PLL_Links_Permalinks {
24
  add_filter( 'upload_dir', array( $this, 'upload_dir' ) );
25
  }
26
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  /**
28
  * Returns the current site url
29
  *
24
  add_filter( 'upload_dir', array( $this, 'upload_dir' ) );
25
  }
26
 
27
+ /**
28
+ * Sets the home urls
29
+ *
30
+ * @since 2.2
31
+ *
32
+ * @param object $language
33
+ */
34
+ protected function set_home_url( $language ) {
35
+ $home_url = $this->home_url( $language );
36
+ $language->set_home_url( $home_url, $home_url ); // Search url and home url are the same
37
+ }
38
+
39
  /**
40
  * Returns the current site url
41
  *
include/links-default.php CHANGED
@@ -78,7 +78,7 @@ class PLL_Links_Default extends PLL_Links_Model {
78
  $url = $_SERVER['REQUEST_URI'];
79
  }
80
 
81
- $pattern = '#lang=('.implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ).')#';
82
  return preg_match( $pattern, trailingslashit( $url ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
83
  }
84
 
78
  $url = $_SERVER['REQUEST_URI'];
79
  }
80
 
81
+ $pattern = '#lang=(' . implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')#';
82
  return preg_match( $pattern, trailingslashit( $url ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
83
  }
84
 
include/links-directory.php CHANGED
@@ -81,7 +81,7 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
81
 
82
  if ( ! empty( $languages ) ) {
83
  $pattern = str_replace( '/', '\/', $this->home . '/' . $this->root );
84
- $pattern = '#' . $pattern . ( $this->options['rewrite'] ? '' : 'language\/' ) . '('.implode( '|', $languages ).')(\/|$)#';
85
  $url = preg_replace( $pattern, $this->home . '/' . $this->root, $url );
86
  }
87
  return $url;
@@ -106,7 +106,7 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
106
 
107
  $pattern = parse_url( $this->home . '/' . $this->root . ( $this->options['rewrite'] ? '' : 'language/' ), PHP_URL_PATH );
108
  $pattern = str_replace( '/', '\/', $pattern );
109
- $pattern = '#' . $pattern . '('. implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')(\/|$)#';
110
  return preg_match( $pattern, trailingslashit( $path ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
111
  }
112
 
@@ -206,7 +206,7 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
206
  * @param string $filter current set of rules being modified
207
  * @param string|bool $archive custom post post type archive name or false if it is not a cpt archive
208
  */
209
- if ( isset( $slug ) && apply_filters( 'pll_modify_rewrite_rule', true, array( $key => $rule ), $filter, false ) ) {
210
  $newrules[ $slug . str_replace( $wp_rewrite->root, '', ltrim( $key, '^' ) ) ] = str_replace(
211
  array( '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?' ),
212
  array( '[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&' ),
@@ -233,7 +233,7 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
233
  if ( $this->options['hide_default'] ) {
234
  $newrules[ $key ] = str_replace( '?', '?lang=' . $this->options['default_lang'] . '&', $rule );
235
  }
236
- } else {
237
  $newrules[ $key ] = $rule;
238
  }
239
  }
@@ -246,7 +246,7 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
246
 
247
  // The home rewrite rule
248
  if ( 'root' == $filter && isset( $slug ) ) {
249
- $newrules[ $slug . '?$' ] = $wp_rewrite->index.'?lang=$matches[1]';
250
  }
251
 
252
  return $newrules;
81
 
82
  if ( ! empty( $languages ) ) {
83
  $pattern = str_replace( '/', '\/', $this->home . '/' . $this->root );
84
+ $pattern = '#' . $pattern . ( $this->options['rewrite'] ? '' : 'language\/' ) . '(' . implode( '|', $languages ) . ')(\/|$)#';
85
  $url = preg_replace( $pattern, $this->home . '/' . $this->root, $url );
86
  }
87
  return $url;
106
 
107
  $pattern = parse_url( $this->home . '/' . $this->root . ( $this->options['rewrite'] ? '' : 'language/' ), PHP_URL_PATH );
108
  $pattern = str_replace( '/', '\/', $pattern );
109
+ $pattern = '#' . $pattern . '(' . implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')(\/|$)#';
110
  return preg_match( $pattern, trailingslashit( $path ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
111
  }
112
 
206
  * @param string $filter current set of rules being modified
207
  * @param string|bool $archive custom post post type archive name or false if it is not a cpt archive
208
  */
209
+ if ( isset( $slug ) && apply_filters( 'pll_modify_rewrite_rule', true, array( $key => $rule ), $filter, false ) ) {
210
  $newrules[ $slug . str_replace( $wp_rewrite->root, '', ltrim( $key, '^' ) ) ] = str_replace(
211
  array( '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?' ),
212
  array( '[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&' ),
233
  if ( $this->options['hide_default'] ) {
234
  $newrules[ $key ] = str_replace( '?', '?lang=' . $this->options['default_lang'] . '&', $rule );
235
  }
236
+ } else {
237
  $newrules[ $key ] = $rule;
238
  }
239
  }
246
 
247
  // The home rewrite rule
248
  if ( 'root' == $filter && isset( $slug ) ) {
249
+ $newrules[ $slug . '?$' ] = $wp_rewrite->index . '?lang=$matches[1]';
250
  }
251
 
252
  return $newrules;
include/links-domain.php CHANGED
@@ -38,7 +38,7 @@ class PLL_Links_Domain extends PLL_Links_Abstract_Domain {
38
  */
39
  public function add_language_to_link( $url, $lang ) {
40
  if ( ! empty( $lang ) && ! empty( $this->hosts[ $lang->slug ] ) ) {
41
- $url = preg_replace( '#:\/\/(' . parse_url( $this->home, PHP_URL_HOST ) . ')($|\/.*)#', '://' . $this->hosts[ $lang->slug ] . "$2", $url );
42
  }
43
  return $url;
44
  }
@@ -54,7 +54,7 @@ class PLL_Links_Domain extends PLL_Links_Abstract_Domain {
54
  */
55
  public function remove_language_from_link( $url ) {
56
  if ( ! empty( $this->hosts ) ) {
57
- $url = preg_replace( '#:\/\/(' . implode( '|', $this->hosts ) . ')($|\/.*)#', '://' . parse_url( $this->home, PHP_URL_HOST ) . "$2", $url );
58
  }
59
  return $url;
60
  }
38
  */
39
  public function add_language_to_link( $url, $lang ) {
40
  if ( ! empty( $lang ) && ! empty( $this->hosts[ $lang->slug ] ) ) {
41
+ $url = preg_replace( '#:\/\/(' . parse_url( $this->home, PHP_URL_HOST ) . ')($|\/.*)#', '://' . $this->hosts[ $lang->slug ] . '$2', $url );
42
  }
43
  return $url;
44
  }
54
  */
55
  public function remove_language_from_link( $url ) {
56
  if ( ! empty( $this->hosts ) ) {
57
+ $url = preg_replace( '#:\/\/(' . implode( '|', $this->hosts ) . ')($|\/.*)#', '://' . parse_url( $this->home, PHP_URL_HOST ) . '$2', $url );
58
  }
59
  return $url;
60
  }
include/links-model.php CHANGED
@@ -65,7 +65,7 @@ abstract class PLL_Links_Model {
65
  */
66
  public function home_url( $lang ) {
67
  $url = trailingslashit( $this->home );
68
- return $this->options['hide_default'] && $lang->slug == $this->options['default_lang'] ? $url: $this->add_language_to_link( $url, $lang );
69
  }
70
 
71
  /**
65
  */
66
  public function home_url( $lang ) {
67
  $url = trailingslashit( $this->home );
68
+ return $this->options['hide_default'] && $lang->slug == $this->options['default_lang'] ? $url : $this->add_language_to_link( $url, $lang );
69
  }
70
 
71
  /**
include/links-subdomain.php CHANGED
@@ -19,7 +19,7 @@ class PLL_Links_Subdomain extends PLL_Links_Abstract_Domain {
19
  */
20
  public function __construct( &$model ) {
21
  parent::__construct( $model );
22
- $this->www = false === strpos( $this->home, '://www.' ) ? '://' : '://www.';
23
  }
24
 
25
  /**
@@ -74,7 +74,7 @@ class PLL_Links_Subdomain extends PLL_Links_Abstract_Domain {
74
  */
75
  public function get_language_from_url( $url = '' ) {
76
  $host = empty( $url ) ? $_SERVER['HTTP_HOST'] : parse_url( $url, PHP_URL_HOST );
77
- $pattern = '#('.implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ).')\.#';
78
  return preg_match( $pattern, trailingslashit( $host ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
79
  }
80
 
19
  */
20
  public function __construct( &$model ) {
21
  parent::__construct( $model );
22
+ $this->www = ( false === strpos( $this->home, '://www.' ) ) ? '://' : '://www.';
23
  }
24
 
25
  /**
74
  */
75
  public function get_language_from_url( $url = '' ) {
76
  $host = empty( $url ) ? $_SERVER['HTTP_HOST'] : parse_url( $url, PHP_URL_HOST );
77
+ $pattern = '#(' . implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')\.#';
78
  return preg_match( $pattern, trailingslashit( $host ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
79
  }
80
 
include/model.php CHANGED
@@ -151,7 +151,7 @@ class PLL_Model {
151
  *
152
  * @since 0.1
153
  *
154
- * @param int|string term_id, tl_term_id, slug or locale of the queried language
155
  * @return object|bool PLL_Language object, false if no language found
156
  */
157
  public function get_language( $value ) {
@@ -294,31 +294,6 @@ class PLL_Model {
294
  return ( is_array( $tax ) && array_intersect( $tax, $taxonomies ) || in_array( $tax, $taxonomies ) );
295
  }
296
 
297
- /**
298
- * Check if translated taxonomy is queried
299
- * Compatible with nested queries introduced in WP 4.1
300
- * @see https://wordpress.org/support/topic/tax_query-bug
301
- *
302
- * @since 1.7
303
- *
304
- * @param array $tax_queries
305
- * @return bool
306
- */
307
- public function have_translated_taxonomy( $tax_queries ) {
308
- foreach ( $tax_queries as $tax_query ) {
309
- if ( isset( $tax_query['taxonomy'] ) && $this->is_translated_taxonomy( $tax_query['taxonomy'] ) && ! ( isset( $tax_query['operator'] ) && 'NOT IN' === $tax_query['operator'] ) ) {
310
- return true;
311
- }
312
-
313
- // Nested queries
314
- elseif ( is_array( $tax_query ) && $this->have_translated_taxonomy( $tax_query ) ) {
315
- return true;
316
- }
317
- }
318
-
319
- return false;
320
- }
321
-
322
  /**
323
  * Return taxonomies that need to be filtered ( post_format like )
324
  *
@@ -575,16 +550,16 @@ class PLL_Model {
575
  *
576
  * @since 1.8
577
  *
578
- * @param string $func function name
579
- * @param array $args function arguments
580
  */
581
  public function __call( $func, $args ) {
582
  $f = $func;
583
 
584
  switch ( $func ) {
585
  case 'get_object_term':
586
- $o = false === strpos( $args[1], 'term' ) ? 'post' : 'term';
587
- break;
588
 
589
  case 'save_translations':
590
  case 'delete_translation':
@@ -593,7 +568,7 @@ class PLL_Model {
593
  case 'join_clause':
594
  $o = ( 'post' == $args[0] || $this->is_translated_post_type( $args[0] ) ) ? 'post' : ( 'term' == $args[0] || $this->is_translated_taxonomy( $args[0] ) ? 'term' : false );
595
  unset( $args[0] );
596
- break;
597
 
598
  case 'set_post_language':
599
  case 'get_post_language':
@@ -605,13 +580,13 @@ class PLL_Model {
605
  $str = explode( '_', $func );
606
  $f = empty( $str[2] ) ? $str[0] : $str[0] . '_' . $str[2];
607
  $o = $str[1];
608
- break;
609
 
610
  case 'where_clause':
611
  case 'get_objects_in_language':
612
  $o = $args[1];
613
  unset( $args[1] );
614
- break;
615
  }
616
 
617
  if ( ! empty( $o ) && is_object( $this->$o ) && method_exists( $this->$o, $f ) ) {
151
  *
152
  * @since 0.1
153
  *
154
+ * @param int|string $value term_id, tl_term_id, slug or locale of the queried language
155
  * @return object|bool PLL_Language object, false if no language found
156
  */
157
  public function get_language( $value ) {
294
  return ( is_array( $tax ) && array_intersect( $tax, $taxonomies ) || in_array( $tax, $taxonomies ) );
295
  }
296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  /**
298
  * Return taxonomies that need to be filtered ( post_format like )
299
  *
550
  *
551
  * @since 1.8
552
  *
553
+ * @param string $func Function name
554
+ * @param array $args Function arguments
555
  */
556
  public function __call( $func, $args ) {
557
  $f = $func;
558
 
559
  switch ( $func ) {
560
  case 'get_object_term':
561
+ $o = ( false === strpos( $args[1], 'term' ) ) ? 'post' : 'term';
562
+ break;
563
 
564
  case 'save_translations':
565
  case 'delete_translation':
568
  case 'join_clause':
569
  $o = ( 'post' == $args[0] || $this->is_translated_post_type( $args[0] ) ) ? 'post' : ( 'term' == $args[0] || $this->is_translated_taxonomy( $args[0] ) ? 'term' : false );
570
  unset( $args[0] );
571
+ break;
572
 
573
  case 'set_post_language':
574
  case 'get_post_language':
580
  $str = explode( '_', $func );
581
  $f = empty( $str[2] ) ? $str[0] : $str[0] . '_' . $str[2];
582
  $o = $str[1];
583
+ break;
584
 
585
  case 'where_clause':
586
  case 'get_objects_in_language':
587
  $o = $args[1];
588
  unset( $args[1] );
589
+ break;
590
  }
591
 
592
  if ( ! empty( $o ) && is_object( $this->$o ) && method_exists( $this->$o, $f ) ) {
include/olt-manager.php CHANGED
@@ -27,7 +27,7 @@ class PLL_OLT_Manager {
27
 
28
  // Overriding load text domain only on front since WP 4.7
29
  // FIXME test get_user_locale for backward compatibility with WP < 4.7
30
- if ( is_admin() && function_exists( 'get_user_locale' ) ) {
31
  return;
32
  }
33
 
@@ -42,7 +42,6 @@ class PLL_OLT_Manager {
42
  // Loads text domains
43
  add_action( 'pll_language_defined', array( $this, 'load_textdomains' ), 2 ); // After PLL_Frontend::pll_language_defined
44
  add_action( 'pll_no_language_defined', array( $this, 'load_textdomains' ) );
45
-
46
  }
47
 
48
  /**
@@ -72,7 +71,6 @@ class PLL_OLT_Manager {
72
  remove_filter( 'gettext_with_context', array( $this, 'gettext_with_context' ), 10, 4 );
73
  $new_locale = get_locale();
74
 
75
-
76
  // Don't try to save time for en_US as some users have theme written in another language
77
  // Now we can load all overriden text domains with the right language
78
  if ( ! empty( $this->list_textdomains ) ) {
@@ -97,14 +95,14 @@ class PLL_OLT_Manager {
97
  }
98
 
99
  // First remove taxonomies and post_types labels that we don't need to translate
100
- $taxonomies = array( 'language', 'term_language', 'term_translations', 'post_translations' );
101
- $post_types = array( 'polylang_mo' );
102
 
103
  // We don't need to translate core taxonomies and post types labels when setting the language from the url
104
  // As they will be translated when registered the second time
105
  if ( ! did_action( 'setup_theme' ) ) {
106
- $taxonomies = array_merge( array( 'category', 'post_tag', 'nav_menu', 'link_category', 'post_format' ), $taxonomies );
107
- $post_types = array_merge( array( 'post', 'page', 'attachment', 'revision', 'nav_menu_item' ), $post_types );
108
  }
109
 
110
  // Translate labels of post types and taxonomies
@@ -162,7 +160,7 @@ class PLL_OLT_Manager {
162
  * @return bool
163
  */
164
  public function load_textdomain_mofile( $mofile, $domain ) {
165
- $this->list_textdomains[ $domain ] = array( 'mo' => $mofile, 'domain' => $domain );
166
  return ''; // Hack to prevent WP loading text domains as we will load them all later
167
  }
168
 
27
 
28
  // Overriding load text domain only on front since WP 4.7
29
  // FIXME test get_user_locale for backward compatibility with WP < 4.7
30
+ if ( is_admin() && ! Polylang::is_ajax_on_front() && function_exists( 'get_user_locale' ) ) {
31
  return;
32
  }
33
 
42
  // Loads text domains
43
  add_action( 'pll_language_defined', array( $this, 'load_textdomains' ), 2 ); // After PLL_Frontend::pll_language_defined
44
  add_action( 'pll_no_language_defined', array( $this, 'load_textdomains' ) );
 
45
  }
46
 
47
  /**
71
  remove_filter( 'gettext_with_context', array( $this, 'gettext_with_context' ), 10, 4 );
72
  $new_locale = get_locale();
73
 
 
74
  // Don't try to save time for en_US as some users have theme written in another language
75
  // Now we can load all overriden text domains with the right language
76
  if ( ! empty( $this->list_textdomains ) ) {
95
  }
96
 
97
  // First remove taxonomies and post_types labels that we don't need to translate
98
+ $taxonomies = get_taxonomies( array( '_pll' => true ) );
99
+ $post_types = get_post_types( array( '_pll' => true ) );
100
 
101
  // We don't need to translate core taxonomies and post types labels when setting the language from the url
102
  // As they will be translated when registered the second time
103
  if ( ! did_action( 'setup_theme' ) ) {
104
+ $taxonomies = array_merge( get_taxonomies( array( '_builtin' => true ) ), $taxonomies );
105
+ $post_types = array_merge( get_post_types( array( '_builtin' => true ) ), $post_types );
106
  }
107
 
108
  // Translate labels of post types and taxonomies
160
  * @return bool
161
  */
162
  public function load_textdomain_mofile( $mofile, $domain ) {
163
+ $this->list_textdomains[] = array( 'mo' => $mofile, 'domain' => $domain );
164
  return ''; // Hack to prevent WP loading text domains as we will load them all later
165
  }
166
 
include/pointer.php CHANGED
@@ -15,17 +15,17 @@ class PLL_Pointer {
15
  *
16
  * list of parameters accepted in $args:
17
  *
18
- * pointer => required, unique identifier of the pointer
19
- * id => required, the pointer will be attached to this html id
20
- * position => optional array, if used both sub parameters are required
21
- * edge => 'top' or 'bottom'
22
- * align => 'right' or 'left'
23
- * width => optional, the width in px
24
- * title => required, title
25
- * content => required, content
26
- * buttons => optional array of arrays, by default the pointer uses the standard dismiss button offered by WP
27
- * label => the label of the button
28
- * link => optional link for the button. By default, the button just dismisses the pointer
29
  *
30
  * @since 1.7.7
31
  *
@@ -105,6 +105,6 @@ class PLL_Pointer {
105
  empty( $this->args['width'] ) ? '' : sprintf( 'pointerWidth: %d,', $this->args['width'] ),
106
  empty( $b ) ? '' : $b
107
  );
108
- echo "<script type='text/javascript'>" .$js. "</script>";
109
  }
110
  }
15
  *
16
  * list of parameters accepted in $args:
17
  *
18
+ * pointer => required, unique identifier of the pointer
19
+ * id => required, the pointer will be attached to this html id
20
+ * position => optional array, if used both sub parameters are required
21
+ * edge => 'top' or 'bottom'
22
+ * align => 'right' or 'left'
23
+ * width => optional, the width in px
24
+ * title => required, title
25
+ * content => required, content
26
+ * buttons => optional array of arrays, by default the pointer uses the standard dismiss button offered by WP
27
+ * label => the label of the button
28
+ * link => optional link for the button. By default, the button just dismisses the pointer
29
  *
30
  * @since 1.7.7
31
  *
105
  empty( $this->args['width'] ) ? '' : sprintf( 'pointerWidth: %d,', $this->args['width'] ),
106
  empty( $b ) ? '' : $b
107
  );
108
+ echo '<script type="text/javascript">' . $js . '</script>';
109
  }
110
  }
include/query.php ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A class to manipulate the language query var in WP_Query
5
+ *
6
+ * @since 2.2
7
+ */
8
+ class PLL_Query {
9
+
10
+ static protected $excludes = array(
11
+ 'p',
12
+ 'post_parent',
13
+ 'attachment',
14
+ 'attachment_id',
15
+ 'name',
16
+ 'pagename',
17
+ 'page_id',
18
+ 'category_name',
19
+ 'tag',
20
+ 'cat',
21
+ 'tag_id',
22
+ 'category__in',
23
+ 'category__and',
24
+ 'post__in',
25
+ 'post_name__in',
26
+ 'tag__in',
27
+ 'tag__and',
28
+ 'tag_slug__in',
29
+ 'tag_slug__and',
30
+ 'post_parent__in',
31
+ );
32
+
33
+ /**
34
+ * Constructor
35
+ *
36
+ * @since 2.2
37
+ *
38
+ * @param array $query Reference to the WP_Query object
39
+ * @param object $model
40
+ */
41
+ public function __construct( &$query, &$model ) {
42
+ $this->query = &$query;
43
+ $this->model = &$model;
44
+ }
45
+
46
+ /**
47
+ * Check if translated taxonomy is queried
48
+ * Compatible with nested queries introduced in WP 4.1
49
+ * @see https://wordpress.org/support/topic/tax_query-bug
50
+ *
51
+ * @since 1.7
52
+ *
53
+ * @param array $tax_queries
54
+ * @return bool
55
+ */
56
+ protected function have_translated_taxonomy( $tax_queries ) {
57
+ foreach ( $tax_queries as $tax_query ) {
58
+ if ( isset( $tax_query['taxonomy'] ) && $this->model->is_translated_taxonomy( $tax_query['taxonomy'] ) && ! ( isset( $tax_query['operator'] ) && 'NOT IN' === $tax_query['operator'] ) ) {
59
+ return true;
60
+ }
61
+
62
+ // Nested queries
63
+ elseif ( is_array( $tax_query ) && $this->have_translated_taxonomy( $tax_query ) ) {
64
+ return true;
65
+ }
66
+ }
67
+
68
+ return false;
69
+ }
70
+
71
+ /**
72
+ * Get queried taxonomies
73
+ *
74
+ * @since 2.2
75
+ *
76
+ * @return array queried taxonomies
77
+ */
78
+ public function get_queried_taxonomies() {
79
+ return isset( $this->query->tax_query->queried_terms ) ? array_keys( wp_list_filter( $this->query->tax_query->queried_terms, array( 'operator' => 'NOT IN' ), 'NOT' ) ) : array();
80
+ }
81
+
82
+ /**
83
+ * Sets the language in query
84
+ * Optimized for ( needs ) WP 3.5+
85
+ *
86
+ * @since 2.2
87
+ *
88
+ * @param object $lang
89
+ */
90
+ public function set_language( $lang ) {
91
+ // Defining directly the tax_query ( rather than setting 'lang' avoids transforming the query by WP )
92
+ $this->query->query_vars['tax_query'][] = array(
93
+ 'taxonomy' => 'language',
94
+ 'field' => 'term_taxonomy_id', // Since WP 3.5
95
+ 'terms' => $lang->term_taxonomy_id,
96
+ 'operator' => 'IN',
97
+ );
98
+ }
99
+
100
+ /**
101
+ * Add the language in query after it has checked that it won't conflict with other query vars
102
+ *
103
+ * @since 2.2
104
+ *
105
+ * @param object $lang Language
106
+ */
107
+ public function filter_query( $lang ) {
108
+ $qvars = &$this->query->query_vars;
109
+
110
+ // Do not filter the query if the language is already specified in another way
111
+ if ( ! isset( $qvars['lang'] ) ) {
112
+ foreach ( self::$excludes as $k ) {
113
+ if ( ! empty( $qvars[ $k ] ) ) {
114
+ return;
115
+ }
116
+ }
117
+
118
+ $taxonomies = array_intersect( $this->model->get_translated_taxonomies(), get_taxonomies( array( '_builtin' => false ) ) );
119
+
120
+ foreach ( $taxonomies as $tax ) {
121
+ $tax = get_taxonomy( $tax );
122
+ if ( ! empty( $qvars[ $tax->query_var ] ) ) {
123
+ return;
124
+ }
125
+ }
126
+
127
+ if ( ! empty( $qvars['tax_query'] ) && is_array( $qvars['tax_query'] ) && $this->have_translated_taxonomy( $qvars['tax_query'] ) ) {
128
+ return;
129
+ }
130
+
131
+ // Filter queries according to the requested language
132
+ if ( ! empty( $lang ) ) {
133
+ $taxonomies = $this->get_queried_taxonomies();
134
+
135
+ if ( $taxonomies && ( empty( $qvars['post_type'] ) || 'any' === $qvars['post_type'] ) ) {
136
+ foreach ( $taxonomies as $taxonomy ) {
137
+ $tax_object = get_taxonomy( $taxonomy );
138
+ if ( $this->model->is_translated_post_type( $tax_object->object_type ) ) {
139
+ $this->set_language( $lang );
140
+ break;
141
+ }
142
+ }
143
+ } elseif ( empty( $qvars['post_type'] ) || $this->model->is_translated_post_type( $qvars['post_type'] ) ) {
144
+ $this->set_language( $lang );
145
+ }
146
+ }
147
+ } else {
148
+ // Do not filter untranslatable post types such as nav_menu_item
149
+ if ( isset( $qvars['post_type'] ) && ! $this->model->is_translated_post_type( $qvars['post_type'] ) ) {
150
+ unset( $qvars['lang'] );
151
+ }
152
+
153
+ // Unset 'all' query var (mainly for admin language filter).
154
+ if ( isset( $qvars['lang'] ) && 'all' === $qvars['lang'] ) {
155
+ unset( $qvars['lang'] );
156
+ }
157
+ }
158
+ }
159
+ }
include/static-pages.php CHANGED
@@ -72,7 +72,7 @@ abstract class PLL_Static_Pages {
72
  *
73
  * @since 1.8
74
  *
75
- * @param array $languages
76
  * @param object $model
77
  */
78
  public static function pll_languages_list( $languages, $model ) {
72
  *
73
  * @since 1.8
74
  *
75
+ * @param array $languages
76
  * @param object $model
77
  */
78
  public static function pll_languages_list( $languages, $model ) {
include/translated-post.php CHANGED
@@ -75,6 +75,7 @@ class PLL_Translated_Post extends PLL_Translated_Object {
75
  *
76
  * @since 1.2
77
  *
 
78
  * @return string join clause
79
  */
80
  public function join_clause( $alias = '' ) {
75
  *
76
  * @since 1.2
77
  *
78
+ * @param string $alias Alias for $wpdb->posts table
79
  * @return string join clause
80
  */
81
  public function join_clause( $alias = '' ) {
include/translated-term.php CHANGED
@@ -22,7 +22,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
22
 
23
  parent::__construct( $model );
24
 
25
- // filters to prime terms cache
26
  add_filter( 'get_terms', array( $this, '_prime_terms_cache' ), 10, 2 );
27
  add_filter( 'wp_get_object_terms', array( $this, 'wp_get_object_terms' ), 10, 3 );
28
 
@@ -41,7 +41,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
41
  $term_id = (int) $term_id;
42
  wp_set_object_terms( $term_id, $lang ? $this->model->get_language( $lang )->tl_term_id : '', 'term_language' );
43
 
44
- // add translation group for correct WXR export
45
  $translations = $this->get_translations( $term_id );
46
  if ( $slug = array_search( $term_id, $translations ) ) {
47
  unset( $translations[ $slug ] );
@@ -80,7 +80,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
80
  $term_id = wpcom_vip_get_term_by( 'slug', $value , $taxonomy )->term_id;
81
  }
82
 
83
- // get the language and make sure it is a PLL_Language object
84
  return isset( $term_id ) && ( $lang = $this->get_object_term( $term_id, 'term_language' ) ) ? $this->model->get_language( $lang->term_id ) : false;
85
  }
86
 
@@ -89,7 +89,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
89
  *
90
  * @since 1.8
91
  *
92
- * @param array $translations: an associative array of translations with language code as key and translation id as value
93
  */
94
  protected function keep_translation_group( $translations ) {
95
  return true;
@@ -107,9 +107,10 @@ class PLL_Translated_Term extends PLL_Translated_Object {
107
  $slug = array_search( $id, $this->get_translations( $id ) ); // in case some plugin stores the same value with different key
108
 
109
  parent::delete_translation( $id );
 
110
 
111
  if ( $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $wpdb->terms WHERE term_id = %d;", $id ) ) ) {
112
- // always keep a group for terms to allow relationships remap when importing from a WXR file
113
  $translations[ $slug ] = $id;
114
  wp_insert_term( $group = uniqid( 'pll_' ), 'term_translations', array( 'description' => serialize( $translations ) ) );
115
  wp_set_object_terms( $id, $group, 'term_translations' );
@@ -145,7 +146,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
145
  }
146
 
147
  if ( ! empty( $term_ids ) ) {
148
- update_object_term_cache( array_unique( $term_ids ), 'term' ); // adds language and translation of terms to cache
149
  }
150
  return $terms;
151
  }
@@ -173,8 +174,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
173
  *
174
  * @since 2.0
175
  *
176
- * @param array $ids An array of term IDs.
177
- * @param string $taxonomy Taxonomy slug.
178
  */
179
  function clean_term_cache( $ids ) {
180
  clean_object_term_cache( $ids, 'term' );
22
 
23
  parent::__construct( $model );
24
 
25
+ // Filters to prime terms cache
26
  add_filter( 'get_terms', array( $this, '_prime_terms_cache' ), 10, 2 );
27
  add_filter( 'wp_get_object_terms', array( $this, 'wp_get_object_terms' ), 10, 3 );
28
 
41
  $term_id = (int) $term_id;
42
  wp_set_object_terms( $term_id, $lang ? $this->model->get_language( $lang )->tl_term_id : '', 'term_language' );
43
 
44
+ // Add translation group for correct WXR export
45
  $translations = $this->get_translations( $term_id );
46
  if ( $slug = array_search( $term_id, $translations ) ) {
47
  unset( $translations[ $slug ] );
80
  $term_id = wpcom_vip_get_term_by( 'slug', $value , $taxonomy )->term_id;
81
  }
82
 
83
+ // Get the language and make sure it is a PLL_Language object
84
  return isset( $term_id ) && ( $lang = $this->get_object_term( $term_id, 'term_language' ) ) ? $this->model->get_language( $lang->term_id ) : false;
85
  }
86
 
89
  *
90
  * @since 1.8
91
  *
92
+ * @param array $translations An associative array of translations with language code as key and translation id as value
93
  */
94
  protected function keep_translation_group( $translations ) {
95
  return true;
107
  $slug = array_search( $id, $this->get_translations( $id ) ); // in case some plugin stores the same value with different key
108
 
109
  parent::delete_translation( $id );
110
+ wp_delete_object_term_relationships( $id, 'term_translations' );
111
 
112
  if ( $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $wpdb->terms WHERE term_id = %d;", $id ) ) ) {
113
+ // Always keep a group for terms to allow relationships remap when importing from a WXR file
114
  $translations[ $slug ] = $id;
115
  wp_insert_term( $group = uniqid( 'pll_' ), 'term_translations', array( 'description' => serialize( $translations ) ) );
116
  wp_set_object_terms( $id, $group, 'term_translations' );
146
  }
147
 
148
  if ( ! empty( $term_ids ) ) {
149
+ update_object_term_cache( array_unique( $term_ids ), 'term' ); // Adds language and translation of terms to cache
150
  }
151
  return $terms;
152
  }
174
  *
175
  * @since 2.0
176
  *
177
+ * @param array $ids An array of term IDs.
 
178
  */
179
  function clean_term_cache( $ids ) {
180
  clean_object_term_cache( $ids, 'term' );
include/walker-dropdown.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /**
4
- * displays languages in a dropdown list
5
  *
6
  * @since 1.2
7
  */
@@ -9,42 +9,51 @@ class PLL_Walker_Dropdown extends Walker {
9
  var $db_fields = array( 'parent' => 'parent', 'id' => 'id' );
10
 
11
  /**
12
- * outputs one element
13
  *
14
  * @since 1.2
15
  *
16
- * @see Walker::start_el
 
 
 
 
17
  */
18
  function start_el( &$output, $element, $depth = 0, $args = array(), $current_object_id = 0 ) {
19
  $value = $args['value'];
20
  $output .= sprintf(
21
- "\t".'<option value="%1$s"%2$s%3$s>%4$s</option>'."\n",
22
  esc_attr( $element->$value ),
23
- empty( $element->locale ) ? '' : sprintf( ' lang="%s"', esc_attr( $element->locale ) ),
24
  isset( $args['selected'] ) && $args['selected'] === $element->$value ? ' selected="selected"' : '',
25
  esc_html( $element->name )
26
  );
27
  }
28
 
29
  /**
30
- * overrides Walker::display_element as expects an object with a parent property
31
  *
32
  * @since 1.2
33
  *
34
- * @see Walker::display_element
 
 
 
 
 
35
  */
36
  function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
37
- $element = (object) $element; // make sure we have an object
38
- $element->parent = $element->id = 0; // don't care about this
39
  parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
40
  }
41
 
42
  /**
43
- * starts the output of the dropdown list
44
  *
45
  * @since 1.2
46
  *
47
- * list of parameters accepted in $args:
48
  *
49
  * flag => display the selected language flag in front of the dropdown if set to 1, defaults to 0
50
  * value => the language field to use as value attribute, defaults to 'slug'
@@ -72,7 +81,7 @@ class PLL_Walker_Dropdown extends Walker {
72
  }
73
 
74
  $output .= sprintf(
75
- '<select name="%1$s"%2$s%3$s%4$s>' . "\n" . '%5$s' . "\n" . '</select>'."\n",
76
  $name = esc_attr( $args['name'] ),
77
  isset( $args['id'] ) && ! $args['id'] ? '' : ' id="' . ( empty( $args['id'] ) ? $name : esc_attr( $args['id'] ) ) . '"',
78
  empty( $args['class'] ) ? '' : ' class="' . esc_attr( $args['class'] ) . '"',
1
  <?php
2
 
3
  /**
4
+ * Displays languages in a dropdown list
5
  *
6
  * @since 1.2
7
  */
9
  var $db_fields = array( 'parent' => 'parent', 'id' => 'id' );
10
 
11
  /**
12
+ * Outputs one element
13
  *
14
  * @since 1.2
15
  *
16
+ * @param string $output Passed by reference. Used to append additional content.
17
+ * @param object $element The data object.
18
+ * @param int $depth Depth of the item.
19
+ * @param array $args An array of additional arguments.
20
+ * @param int $current_object_id ID of the current item.
21
  */
22
  function start_el( &$output, $element, $depth = 0, $args = array(), $current_object_id = 0 ) {
23
  $value = $args['value'];
24
  $output .= sprintf(
25
+ "\t" . '<option value="%1$s"%2$s%3$s>%4$s</option>' . "\n",
26
  esc_attr( $element->$value ),
27
+ method_exists( $element, 'get_locale' ) ? sprintf( ' lang="%s"', esc_attr( $element->get_locale( 'display' ) ) ) : '',
28
  isset( $args['selected'] ) && $args['selected'] === $element->$value ? ' selected="selected"' : '',
29
  esc_html( $element->name )
30
  );
31
  }
32
 
33
  /**
34
+ * Overrides Walker::display_element as expects an object with a parent property
35
  *
36
  * @since 1.2
37
  *
38
+ * @param object $element Data object.
39
+ * @param array $children_elements List of elements to continue traversing.
40
+ * @param int $max_depth Max depth to traverse.
41
+ * @param int $depth Depth of current element.
42
+ * @param array $args An array of arguments.
43
+ * @param string $output Passed by reference. Used to append additional content.
44
  */
45
  function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
46
+ $element = (object) $element; // Make sure we have an object
47
+ $element->parent = $element->id = 0; // Don't care about this
48
  parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
49
  }
50
 
51
  /**
52
+ * Starts the output of the dropdown list
53
  *
54
  * @since 1.2
55
  *
56
+ * List of parameters accepted in $args:
57
  *
58
  * flag => display the selected language flag in front of the dropdown if set to 1, defaults to 0
59
  * value => the language field to use as value attribute, defaults to 'slug'
81
  }
82
 
83
  $output .= sprintf(
84
+ '<select name="%1$s"%2$s%3$s%4$s>' . "\n" . '%5$s' . "\n" . '</select>' . "\n",
85
  $name = esc_attr( $args['name'] ),
86
  isset( $args['id'] ) && ! $args['id'] ? '' : ' id="' . ( empty( $args['id'] ) ? $name : esc_attr( $args['id'] ) ) . '"',
87
  empty( $args['class'] ) ? '' : ' class="' . esc_attr( $args['class'] ) . '"',
include/walker-list.php CHANGED
@@ -13,7 +13,11 @@ class PLL_Walker_List extends Walker {
13
  *
14
  * @since 1.2
15
  *
16
- * @see Walker::start_el
 
 
 
 
17
  */
18
  function start_el( &$output, $element, $depth = 0, $args = array(), $current_object_id = 0 ) {
19
  $output .= sprintf(
@@ -23,8 +27,8 @@ class PLL_Walker_List extends Walker {
23
  esc_url( $element->url ),
24
  $element->flag,
25
  $args['show_flags'] && $args['show_names'] ? '<span style="margin-left:0.3em;">' . esc_html( $element->name ) . '</span>' : esc_html( $element->name ),
26
- $args['item_spacing'] === 'discard' ? '' : "\t",
27
- $args['item_spacing'] === 'discard' ? '' : "\n"
28
  );
29
  }
30
 
@@ -33,7 +37,12 @@ class PLL_Walker_List extends Walker {
33
  *
34
  * @since 1.2
35
  *
36
- * @see Walker::display_element
 
 
 
 
 
37
  */
38
  function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
39
  $element = (object) $element; // Make sure we have an object
13
  *
14
  * @since 1.2
15
  *
16
+ * @param string $output Passed by reference. Used to append additional content.
17
+ * @param object $element The data object.
18
+ * @param int $depth Depth of the item.
19
+ * @param array $args An array of additional arguments.
20
+ * @param int $current_object_id ID of the current item.
21
  */
22
  function start_el( &$output, $element, $depth = 0, $args = array(), $current_object_id = 0 ) {
23
  $output .= sprintf(
27
  esc_url( $element->url ),
28
  $element->flag,
29
  $args['show_flags'] && $args['show_names'] ? '<span style="margin-left:0.3em;">' . esc_html( $element->name ) . '</span>' : esc_html( $element->name ),
30
+ 'discard' === $args['item_spacing'] ? '' : "\t",
31
+ 'discard' === $args['item_spacing'] ? '' : "\n"
32
  );
33
  }
34
 
37
  *
38
  * @since 1.2
39
  *
40
+ * @param object $element Data object.
41
+ * @param array $children_elements List of elements to continue traversing.
42
+ * @param int $max_depth Max depth to traverse.
43
+ * @param int $depth Depth of current element.
44
+ * @param array $args An array of arguments.
45
+ * @param string $output Passed by reference. Used to append additional content.
46
  */
47
  function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
48
  $element = (object) $element; // Make sure we have an object
include/widget-languages.php CHANGED
@@ -45,7 +45,7 @@ class PLL_Widget_Languages extends WP_Widget {
45
  echo $args['before_title'] . $title . $args['after_title'];
46
  }
47
  if ( $instance['dropdown'] ) {
48
- echo '<label class="screen-reader-text" for="' . esc_attr( 'lang_choice_' . $instance['dropdown'] ) . '">' . esc_html__( 'Choose a language', 'polylang' ). '</label>';
49
  echo $list;
50
  } else {
51
  echo "<ul>\n" . $list . "</ul>\n";
@@ -126,7 +126,8 @@ class PLL_Widget_Languages extends WP_Widget {
126
  return;
127
  }
128
 
129
- $done = true; ?>
 
130
  <script type='text/javascript'>
131
  //<![CDATA[
132
  jQuery( document ).ready( function( $ ) {
@@ -152,6 +153,7 @@ class PLL_Widget_Languages extends WP_Widget {
152
  } );
153
  } );
154
  //]]>
155
- </script><?php
 
156
  }
157
  }
45
  echo $args['before_title'] . $title . $args['after_title'];
46
  }
47
  if ( $instance['dropdown'] ) {
48
+ echo '<label class="screen-reader-text" for="' . esc_attr( 'lang_choice_' . $instance['dropdown'] ) . '">' . esc_html__( 'Choose a language', 'polylang' ) . '</label>';
49
  echo $list;
50
  } else {
51
  echo "<ul>\n" . $list . "</ul>\n";
126
  return;
127
  }
128
 
129
+ $done = true;
130
+ ?>
131
  <script type='text/javascript'>
132
  //<![CDATA[
133
  jQuery( document ).ready( function( $ ) {
153
  } );
154
  } );
155
  //]]>
156
+ </script>
157
+ <?php
158
  }
159
  }
install/install-base.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /**
4
- * a generic activation / de-activation class compatble with multisite
5
  *
6
  * @since 1.7
7
  */
@@ -9,23 +9,25 @@ class PLL_Install_Base {
9
  protected $plugin_basename;
10
 
11
  /**
12
- * constructor
13
  *
14
  * @since 1.7
 
 
15
  */
16
  public function __construct( $plugin_basename ) {
17
  $this->plugin_basename = $plugin_basename;
18
 
19
- // manages plugin activation and deactivation
20
  register_activation_hook( $plugin_basename, array( $this, 'activate' ) );
21
  register_deactivation_hook( $plugin_basename, array( $this, 'deactivate' ) );
22
 
23
- // blog creation on multisite
24
- add_action( 'wpmu_new_blog', array( $this, 'wpmu_new_blog' ), 5 ); // before WP attempts to send mails which can break on some PHP versions
25
  }
26
 
27
  /**
28
- * allows to detect plugin deactivation
29
  *
30
  * @since 1.7
31
  *
@@ -36,14 +38,15 @@ class PLL_Install_Base {
36
  }
37
 
38
  /**
39
- * activation or deactivation for all blogs
40
  *
41
  * @since 1.2
42
  *
43
- * @param string $what either 'activate' or 'deactivate'
 
44
  */
45
  protected function do_for_all_blogs( $what, $networkwide ) {
46
- // network
47
  if ( is_multisite() && $networkwide ) {
48
  global $wpdb;
49
 
@@ -54,50 +57,54 @@ class PLL_Install_Base {
54
  restore_current_blog();
55
  }
56
 
57
- // single blog
58
  else {
59
  'activate' == $what ? $this->_activate() : $this->_deactivate();
60
  }
61
  }
62
 
63
  /**
64
- * plugin activation for multisite
65
  *
66
  * @since 1.7
 
 
67
  */
68
  public function activate( $networkwide ) {
69
  $this->do_for_all_blogs( 'activate', $networkwide );
70
  }
71
 
72
  /**
73
- * plugin activation
74
  *
75
  * @since 0.5
76
  */
77
  protected function _activate() {
78
- // can be overriden in child class
79
  }
80
 
81
  /**
82
- * plugin deactivation for multisite
83
  *
84
  * @since 0.1
 
 
85
  */
86
  public function deactivate( $networkwide ) {
87
  $this->do_for_all_blogs( 'deactivate', $networkwide );
88
  }
89
 
90
  /**
91
- * plugin deactivation
92
  *
93
  * @since 0.5
94
  */
95
  protected function _deactivate() {
96
- // can be overriden in child class
97
  }
98
 
99
  /**
100
- * blog creation on multisite ( to set default options )
101
  *
102
  * @since 0.9.4
103
  *
1
  <?php
2
 
3
  /**
4
+ * A generic activation / de-activation class compatble with multisite
5
  *
6
  * @since 1.7
7
  */
9
  protected $plugin_basename;
10
 
11
  /**
12
+ * Constructor
13
  *
14
  * @since 1.7
15
+ *
16
+ * @param string $plugin_basename Plugin basename
17
  */
18
  public function __construct( $plugin_basename ) {
19
  $this->plugin_basename = $plugin_basename;
20
 
21
+ // Manages plugin activation and deactivation
22
  register_activation_hook( $plugin_basename, array( $this, 'activate' ) );
23
  register_deactivation_hook( $plugin_basename, array( $this, 'deactivate' ) );
24
 
25
+ // Blog creation on multisite
26
+ add_action( 'wpmu_new_blog', array( $this, 'wpmu_new_blog' ), 5 ); // Before WP attempts to send mails which can break on some PHP versions
27
  }
28
 
29
  /**
30
+ * Allows to detect plugin deactivation
31
  *
32
  * @since 1.7
33
  *
38
  }
39
 
40
  /**
41
+ * Activation or deactivation for all blogs
42
  *
43
  * @since 1.2
44
  *
45
+ * @param string $what Either 'activate' or 'deactivate'
46
+ * @param bool $networkwide
47
  */
48
  protected function do_for_all_blogs( $what, $networkwide ) {
49
+ // Network
50
  if ( is_multisite() && $networkwide ) {
51
  global $wpdb;
52
 
57
  restore_current_blog();
58
  }
59
 
60
+ // Single blog
61
  else {
62
  'activate' == $what ? $this->_activate() : $this->_deactivate();
63
  }
64
  }
65
 
66
  /**
67
+ * Plugin activation for multisite
68
  *
69
  * @since 1.7
70
+ *
71
+ * @param bool $networkwide
72
  */
73
  public function activate( $networkwide ) {
74
  $this->do_for_all_blogs( 'activate', $networkwide );
75
  }
76
 
77
  /**
78
+ * Plugin activation
79
  *
80
  * @since 0.5
81
  */
82
  protected function _activate() {
83
+ // Can be overriden in child class
84
  }
85
 
86
  /**
87
+ * Plugin deactivation for multisite
88
  *
89
  * @since 0.1
90
+ *
91
+ * @param bool $networkwide
92
  */
93
  public function deactivate( $networkwide ) {
94
  $this->do_for_all_blogs( 'deactivate', $networkwide );
95
  }
96
 
97
  /**
98
+ * Plugin deactivation
99
  *
100
  * @since 0.5
101
  */
102
  protected function _deactivate() {
103
+ // Can be overriden in child class
104
  }
105
 
106
  /**
107
+ * Blog creation on multisite ( to set default options )
108
  *
109
  * @since 0.9.4
110
  *
install/install.php CHANGED
@@ -8,16 +8,18 @@
8
  class PLL_Install extends PLL_Install_Base {
9
 
10
  /**
11
- * plugin activation for multisite
12
  *
13
  * @since 0.1
 
 
14
  */
15
  public function activate( $networkwide ) {
16
  global $wp_version;
17
 
18
  Polylang::define_constants();
19
 
20
- load_plugin_textdomain( 'polylang', false, basename( POLYLANG_DIR ).'/languages' ); // plugin i18n
21
 
22
  if ( version_compare( $wp_version, PLL_MIN_WP_VERSION , '<' ) ) {
23
  die( sprintf( '<p style = "font-family: sans-serif; font-size: 12px; color: #333; margin: -5px">%s</p>',
@@ -32,7 +34,7 @@ class PLL_Install extends PLL_Install_Base {
32
  }
33
 
34
  /**
35
- * get default Polylang options
36
  *
37
  * @since 1.8
38
  *
@@ -56,40 +58,40 @@ class PLL_Install extends PLL_Install_Base {
56
  }
57
 
58
  /**
59
- * plugin activation
60
  *
61
  * @since 0.5
62
  */
63
  protected function _activate() {
64
  if ( $options = get_option( 'polylang' ) ) {
65
- // check if we will be able to upgrade
66
  if ( version_compare( $options['version'], POLYLANG_VERSION, '<' ) ) {
67
  $upgrade = new PLL_Upgrade( $options );
68
  $upgrade->can_activate();
69
  }
70
  }
71
- // defines default values for options in case this is the first installation
72
  else {
73
  update_option( 'polylang', self::get_default_options() );
74
  }
75
 
76
- // avoid 1 query on every pages if no wpml strings is registered
77
  if ( ! get_option( 'polylang_wpml_strings' ) ) {
78
  update_option( 'polylang_wpml_strings', array() );
79
  }
80
 
81
- // don't use flush_rewrite_rules at network activation. See #32471
82
- // thanks to RavanH for the trick. See https://polylang.wordpress.com/2015/06/10/polylang-1-7-6-and-multisite/
83
- // rewrite rules are created at next page load :)
84
  delete_option( 'rewrite_rules' );
85
  }
86
 
87
  /**
88
- * plugin deactivation
89
  *
90
  * @since 0.5
91
  */
92
  protected function _deactivate() {
93
- delete_option( 'rewrite_rules' ); // don't use flush_rewrite_rules at network activation. See #32471
94
  }
95
  }
8
  class PLL_Install extends PLL_Install_Base {
9
 
10
  /**
11
+ * Plugin activation for multisite
12
  *
13
  * @since 0.1
14
+ *
15
+ * @param bool $networkwide
16
  */
17
  public function activate( $networkwide ) {
18
  global $wp_version;
19
 
20
  Polylang::define_constants();
21
 
22
+ load_plugin_textdomain( 'polylang', false, basename( POLYLANG_DIR ) . '/languages' ); // plugin i18n
23
 
24
  if ( version_compare( $wp_version, PLL_MIN_WP_VERSION , '<' ) ) {
25
  die( sprintf( '<p style = "font-family: sans-serif; font-size: 12px; color: #333; margin: -5px">%s</p>',
34
  }
35
 
36
  /**
37
+ * Get default Polylang options
38
  *
39
  * @since 1.8
40
  *
58
  }
59
 
60
  /**
61
+ * Plugin activation
62
  *
63
  * @since 0.5
64
  */
65
  protected function _activate() {
66
  if ( $options = get_option( 'polylang' ) ) {
67
+ // Check if we will be able to upgrade
68
  if ( version_compare( $options['version'], POLYLANG_VERSION, '<' ) ) {
69
  $upgrade = new PLL_Upgrade( $options );
70
  $upgrade->can_activate();
71
  }
72
  }
73
+ // Defines default values for options in case this is the first installation
74
  else {
75
  update_option( 'polylang', self::get_default_options() );
76
  }
77
 
78
+ // Avoid 1 query on every pages if no wpml strings is registered
79
  if ( ! get_option( 'polylang_wpml_strings' ) ) {
80
  update_option( 'polylang_wpml_strings', array() );
81
  }
82
 
83
+ // Don't use flush_rewrite_rules at network activation. See #32471
84
+ // Thanks to RavanH for the trick. See https://polylang.wordpress.com/2015/06/10/polylang-1-7-6-and-multisite/
85
+ // Rewrite rules are created at next page load :)
86
  delete_option( 'rewrite_rules' );
87
  }
88
 
89
  /**
90
+ * Plugin deactivation
91
  *
92
  * @since 0.5
93
  */
94
  protected function _deactivate() {
95
+ delete_option( 'rewrite_rules' ); // Don't use flush_rewrite_rules at network activation. See #32471
96
  }
97
  }
install/upgrade.php CHANGED
@@ -12,6 +12,8 @@ class PLL_Upgrade {
12
  * Constructor
13
  *
14
  * @since 1.2
 
 
15
  */
16
  public function __construct( &$options ) {
17
  $this->options = &$options;
@@ -87,7 +89,7 @@ class PLL_Upgrade {
87
  * @since 1.2
88
  */
89
  public function _upgrade() {
90
- 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' ) as $version ) {
91
  if ( version_compare( $this->options['version'], $version, '<' ) ) {
92
  call_user_func( array( $this, 'upgrade_' . str_replace( '.', '_', $version ) ) );
93
  }
@@ -231,7 +233,7 @@ class PLL_Upgrade {
231
  }
232
 
233
  // Get all terms with their term_id
234
- $terms = $wpdb->get_results( "SELECT term_id, slug FROM $wpdb->terms WHERE slug IN ( " . implode( ',', $slugs ) . " )" );
235
 
236
  // Prepare terms taxonomy relationship
237
  foreach ( $terms as $term ) {
@@ -585,4 +587,12 @@ class PLL_Upgrade {
585
  }
586
  }
587
 
 
 
 
 
 
 
 
 
588
  }
12
  * Constructor
13
  *
14
  * @since 1.2
15
+ *
16
+ * @param array $options Polylang options
17
  */
18
  public function __construct( &$options ) {
19
  $this->options = &$options;
89
  * @since 1.2
90
  */
91
  public function _upgrade() {
92
+ 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.2' ) as $version ) {
93
  if ( version_compare( $this->options['version'], $version, '<' ) ) {
94
  call_user_func( array( $this, 'upgrade_' . str_replace( '.', '_', $version ) ) );
95
  }
233
  }
234
 
235
  // Get all terms with their term_id
236
+ $terms = $wpdb->get_results( "SELECT term_id, slug FROM $wpdb->terms WHERE slug IN ( " . implode( ',', $slugs ) . ' )' );
237
 
238
  // Prepare terms taxonomy relationship
239
  foreach ( $terms as $term ) {
587
  }
588
  }
589
 
590
+ /**
591
+ * Upgrades if the previous version is < 2.2
592
+ *
593
+ * @since 2.2
594
+ */
595
+ protected function upgrade_2_2() {
596
+ delete_transient( 'pll_languages_list' ); // Deletes language cache (due to 'redirect_lang' option removed for subdomains and multiple domains)
597
+ }
598
  }
js/admin.js CHANGED
@@ -171,6 +171,7 @@ jQuery( document ).ready(function( $ ) {
171
  pll_toggle( $( '#pll-domains-table' ), 3 == value );
172
  pll_toggle( $( "#pll-hide-default" ), 3 > value );
173
  pll_toggle( $( "#pll-rewrite" ), 2 > value );
 
174
  });
175
 
176
  // settings license
171
  pll_toggle( $( '#pll-domains-table' ), 3 == value );
172
  pll_toggle( $( "#pll-hide-default" ), 3 > value );
173
  pll_toggle( $( "#pll-rewrite" ), 2 > value );
174
+ pll_toggle( $( "#pll-redirect-lang" ), 2 > value );
175
  });
176
 
177
  // settings license
js/admin.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready(function(e){function t(){var t=e(this).val();if(t){var n=e(this).iconselectmenu("widget").children(":last"),i=e('<img class="ui-icon" >').appendTo(n);i.attr("src",pll_flag_base_url+t+".png")}}var n;e("table.languages").on({focusin:function(){clearTimeout(n),focusedRowActions=e(this).find(".row-actions"),e(".row-actions").not(this).removeClass("visible"),focusedRowActions.addClass("visible")},focusout:function(){n=setTimeout(function(){focusedRowActions.removeClass("visible")},30)}},"tr"),e.widget("custom.iconselectmenu",e.ui.selectmenu,{_renderItem:function(t,n){var i=e("<li>",{text:n.label});return n.value&&e("<img>",{src:pll_flag_base_url+n.value+".png","class":"ui-icon"}).appendTo(i),i.appendTo(t)}}),e("#flag_list").iconselectmenu({create:t,select:t}),e("#lang_list").change(function(){var n=e(this).val().split(":"),i=e("select option:selected").text().split(" - ");e("#lang_slug").val(n[0]),e("#lang_locale").val(n[1]),e('input[name="rtl"]').val([n[2]]),e("#lang_name").val(i[0]),e('#flag_list option[value="'+n[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"),n=t.attr("id").split("-"),i={action:"pll_save_options",pll_ajax_settings:!0,module:n[n.length-1],_pll_nonce:e("#_pll_nonce").val()};i=t.find(":input").serialize()+"&"+e.param(i),e.post(ajaxurl,i,function(n){var i=wpAjax.parseAjaxResponse(n,"ajax-response");e.each(i.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>'),i=commonL10n.dismiss||"";n.find(".screen-reader-text").text(i),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)}),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)})})});
1
+ jQuery(document).ready(function(e){function t(){var t=e(this).val();if(t){var n=e(this).iconselectmenu("widget").children(":last"),i=e('<img class="ui-icon" >').appendTo(n);i.attr("src",pll_flag_base_url+t+".png")}}var n;e("table.languages").on({focusin:function(){clearTimeout(n),focusedRowActions=e(this).find(".row-actions"),e(".row-actions").not(this).removeClass("visible"),focusedRowActions.addClass("visible")},focusout:function(){n=setTimeout(function(){focusedRowActions.removeClass("visible")},30)}},"tr"),e.widget("custom.iconselectmenu",e.ui.selectmenu,{_renderItem:function(t,n){var i=e("<li>",{text:n.label});return n.value&&e("<img>",{src:pll_flag_base_url+n.value+".png","class":"ui-icon"}).appendTo(i),i.appendTo(t)}}),e("#flag_list").iconselectmenu({create:t,select:t}),e("#lang_list").change(function(){var n=e(this).val().split(":"),i=e("select option:selected").text().split(" - ");e("#lang_slug").val(n[0]),e("#lang_locale").val(n[1]),e('input[name="rtl"]').val([n[2]]),e("#lang_name").val(i[0]),e('#flag_list option[value="'+n[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"),n=t.attr("id").split("-"),i={action:"pll_save_options",pll_ajax_settings:!0,module:n[n.length-1],_pll_nonce:e("#_pll_nonce").val()};i=t.find(":input").serialize()+"&"+e.param(i),e.post(ajaxurl,i,function(n){var i=wpAjax.parseAjaxResponse(n,"ajax-response");e.each(i.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>'),i=commonL10n.dismiss||"";n.find(".screen-reader-text").text(i),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)})})});
js/post.js CHANGED
@@ -161,9 +161,13 @@ jQuery( document ).ready(function( $ ) {
161
 
162
  // ajax for changing the post's language in the languages metabox
163
  $( '.post_lang_choice' ).change(function() {
 
 
 
 
164
  var data = {
165
  action: 'post_lang_choice',
166
- lang: $( this ).val(),
167
  post_type: $( '#post_type' ).val(),
168
  taxonomies: taxonomies,
169
  post_id: $( '#post_ID' ).val(),
@@ -205,6 +209,11 @@ jQuery( document ).ready(function( $ ) {
205
  var id = $( this ).attr( 'id' );
206
  tagBox.get( id );
207
  });
 
 
 
 
 
208
  });
209
  });
210
 
@@ -212,7 +221,7 @@ jQuery( document ).ready(function( $ ) {
212
  function init_translations() {
213
  $( '.tr_lang' ).each(function(){
214
  var tr_lang = $( this ).attr( 'id' ).substring( 8 );
215
- var td = $( this ).parent().siblings( '.pll-edit-column' );
216
 
217
  $( this ).autocomplete({
218
  minLength: 0,
161
 
162
  // ajax for changing the post's language in the languages metabox
163
  $( '.post_lang_choice' ).change(function() {
164
+ var value = $( this ).val();
165
+ var lang = $( this ).children( 'option[value="' + value + '"]' ).attr( 'lang' );
166
+ var dir = $( '.pll-translation-column > span[lang="' + lang + '"]' ).attr( 'dir' );
167
+
168
  var data = {
169
  action: 'post_lang_choice',
170
+ lang: value,
171
  post_type: $( '#post_type' ).val(),
172
  taxonomies: taxonomies,
173
  post_id: $( '#post_ID' ).val(),
209
  var id = $( this ).attr( 'id' );
210
  tagBox.get( id );
211
  });
212
+
213
+ // Modifies the text direction
214
+ $( 'body' ).removeClass( 'pll-dir-rtl' ).removeClass( 'pll-dir-ltr' ).addClass( 'pll-dir-' + dir );
215
+ $( '#content_ifr' ).contents().find( 'html' ).attr( 'lang', lang ).attr( 'dir', dir );
216
+ $( '#content_ifr' ).contents().find( 'body' ).attr( 'dir', dir );
217
  });
218
  });
219
 
221
  function init_translations() {
222
  $( '.tr_lang' ).each(function(){
223
  var tr_lang = $( this ).attr( 'id' ).substring( 8 );
224
+ var td = $( this ).parent().parent().siblings( '.pll-edit-column' );
225
 
226
  $( this ).autocomplete({
227
  minLength: 0,
js/post.min.js CHANGED
@@ -1 +1 @@
1
- !function(a){a.ajaxPrefilter(function(t){"string"!=typeof t.data||-1===t.url.indexOf("action=ajax-tag-search")&&-1===t.data.indexOf("action=ajax-tag-search")||!(lang=a(".post_lang_choice").val())&&!(lang=a(':input[name="inline_lang_choice"]').val())||(t.data="lang="+lang+"&"+t.data)})}(jQuery),function(a){tagBox.get=function(t){var n=t.substr(t.indexOf("-")+1),e={action:"get-tagcloud",lang:a(".post_lang_choice").val(),tax:n};a.post(ajaxurl,e,function(e,i){0!=e&&"success"==i||(e=wpAjax.broken),e=a('<p id="tagcloud-'+n+'" class="the-tagcloud">'+e+"</p>"),a("a",e).click(function(){return tagBox.flushTags(a(this).closest(".inside").children(".tagsdiv"),this),!1}),(v=a(".the-tagcloud").css("display"))?(a(".the-tagcloud").replaceWith(e),a(".the-tagcloud").css("display",v)):a("#"+t).after(e)})}}(jQuery),function(a){a(document).bind("DOMNodeInserted",function(t){function n(t){"undefined"!=typeof pll_term_languages&&a.each(pll_term_languages,function(n,e){a.each(e,function(e,i){a.each(i,function(i){id="#"+e+"-"+pll_term_languages[n][e][i],t==n?a(id).show():a(id).hide()})})})}function e(t){"undefined"!=typeof pll_page_languages&&a.each(pll_page_languages,function(n,e){a.each(e,function(e){v=a('#post_parent option[value="'+pll_page_languages[n][e]+'"]'),t==n?v.show():v.hide()})})}var i=a(t.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=a("#lang_"+l).html();s.val(o),n(o),e(o),s.change(function(){n(a(this).val()),e(a(this).val())})}}})}(jQuery),function(a){a(document).ajaxSuccess(function(t,n,e){function i(t){var n=new Array;a(".translation_"+t).each(function(){n.push(a(this).parent().parent().attr("id").substring(5))});var e={action:"pll_update_post_rows",post_id:t,translations:n.join(","),post_type:a("input[name='post_type']").val(),screen:a("input[name='screen']").val(),_pll_nonce:a("input[name='_inline_edit']").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("#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(a){function t(){a(".tr_lang").each(function(){var t=a(this).attr("id").substring(8),n=a(this).parent().siblings(".pll-edit-column");a(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+a(".post_lang_choice").val()+"&translation_language="+t+"&post_type="+a("#post_type").val()+"&_pll_nonce="+a("#_pll_nonce").val(),select:function(e,i){a("#htr_lang_"+t).val(i.item.id),n.html(i.item.link)}}),a(this).blur(function(){a(this).val()||(a("#htr_lang_"+t).val(0),n.html(n.siblings(".hidden").children().clone()))})})}var n=new Array;a(".categorydiv").each(function(){var t,e,i=a(this).attr("id");t=i.split("-"),t.shift(),e=t.join("-"),n.push(e),a("#"+e+"-add-submit").before(a("<input />").attr("type","hidden").attr("id",e+"-lang").attr("name","term_lang_choice").attr("value",a(".post_lang_choice").val()))}),a(".post_lang_choice").change(function(){var e={action:"post_lang_choice",lang:a(this).val(),post_type:a("#post_type").val(),taxonomies:n,post_id:a("#post_ID").val(),_pll_nonce:a("#_pll_nonce").val()};a.post(ajaxurl,e,function(n){var e=wpAjax.parseAjaxResponse(n,"ajax-response");a.each(e.responses,function(){switch(this.what){case"translations":a(".translations").html(this.data),t();break;case"taxonomy":var n=this.data;a("#"+n+"checklist").html(this.supplemental.all),a("#"+n+"checklist-pop").html(this.supplemental.populars),a("#new"+n+"_parent").replaceWith(this.supplemental.dropdown),a("#"+n+"-lang").val(a(".post_lang_choice").val());break;case"pages":a("#parent_id").html(this.data);break;case"flag":a(".pll-select-flag").html(this.data);break;case"permalink":var e=a("#edit-slug-box");"-1"!=this.data&&e.children().length&&e.html(this.data)}}),a(".tagcloud-link").each(function(){var t=a(this).attr("id");tagBox.get(t)})})}),t()});
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('<p id="tagcloud-'+n+'" class="the-tagcloud">'+e+"</p>"),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()});
js/term.js CHANGED
@@ -93,7 +93,7 @@ jQuery( document ).ready(function( $ ) {
93
  function init_translations() {
94
  $( '.tr_lang' ).each(function(){
95
  var tr_lang = $( this ).attr( 'id' ).substring( 8 );
96
- var td = $( this ).parent().siblings( '.pll-edit-column' );
97
 
98
  $( this ).autocomplete({
99
  minLength: 0,
@@ -126,9 +126,13 @@ jQuery( document ).ready(function( $ ) {
126
 
127
  // ajax for changing the term's language
128
  $( '#term_lang_choice' ).change(function() {
 
 
 
 
129
  var data = {
130
  action: 'term_lang_choice',
131
- lang: $( this ).val(),
132
  from_tag: $( "input[name='from_tag']" ).val(),
133
  term_id: $( "input[name='tag_ID']" ).val(),
134
  taxonomy: $( "input[name='taxonomy']" ).val(),
@@ -155,6 +159,9 @@ jQuery( document ).ready(function( $ ) {
155
  break;
156
  }
157
  });
 
 
 
158
  });
159
  });
160
  });
93
  function init_translations() {
94
  $( '.tr_lang' ).each(function(){
95
  var tr_lang = $( this ).attr( 'id' ).substring( 8 );
96
+ var td = $( this ).parent().parent().siblings( '.pll-edit-column' );
97
 
98
  $( this ).autocomplete({
99
  minLength: 0,
126
 
127
  // ajax for changing the term's language
128
  $( '#term_lang_choice' ).change(function() {
129
+ var value = $( this ).val();
130
+ var lang = $( this ).children( 'option[value="' + value + '"]' ).attr( 'lang' );
131
+ var dir = $( '.pll-translation-column > span[lang="' + lang + '"]' ).attr( 'dir' );
132
+
133
  var data = {
134
  action: 'term_lang_choice',
135
+ lang: value,
136
  from_tag: $( "input[name='from_tag']" ).val(),
137
  term_id: $( "input[name='tag_ID']" ).val(),
138
  taxonomy: $( "input[name='taxonomy']" ).val(),
159
  break;
160
  }
161
  });
162
+
163
+ // Modifies the text direction
164
+ $( 'body' ).removeClass( 'pll-dir-rtl' ).removeClass( 'pll-dir-ltr' ).addClass( 'pll-dir-' + dir );
165
  });
166
  });
167
  });
js/term.min.js CHANGED
@@ -1 +1 @@
1
- !function(a){a(document).bind("DOMNodeInserted",function(t){var e=a(t.target);if("inline-edit"==e.attr("id")){var n=e.prev().attr("id").replace("tag-","");if(n>0){var i=e.find(':input[name="inline_lang_choice"]'),l=a("#lang_"+n).html();i.val(l);var s=a("#default_cat_"+n).html();n==s&&i.prop("disabled",!0)}}})}(jQuery),function(a){a(document).ajaxSuccess(function(t,e,n){function i(t){var e=new Array;a(".translation_"+t).each(function(){e.push(a(this).parent().parent().attr("id").substring(4))});var n={action:"pll_update_term_rows",term_id:t,translations:e.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,n,function(t){if(t){var e=wpAjax.parseAjaxResponse(t,"ajax-response");a.each(e.responses,function(){"row"==this.what&&a("#tag-"+this.supplemental.term_id).replaceWith(this.data)})}})}var l=wpAjax.unserialize(n.data);if("undefined"!=typeof l.action)switch(l.action){case"add-tag":res=wpAjax.parseAjaxResponse(e.responseXML,"ajax-response"),a.each(res.responses,function(){"term"==this.what&&i(this.supplemental.term_id)}),a(".htr_lang").val(0);break;case"delete-tag":i(l.tag_ID);break;case"inline-save-tax":i(l.tax_ID)}})}(jQuery),jQuery(document).ready(function(a){function t(){a(".tr_lang").each(function(){var t=a(this).attr("id").substring(8),e=a(this).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(n,i){a("#htr_lang_"+t).val(i.item.id),e.html(i.item.link)}}),a(this).blur(function(){a(this).val()||(a("#htr_lang_"+t).val(0),e.html(e.siblings(".hidden").children().clone()))})})}t(),a("#term_lang_choice").change(function(){var e={action:"term_lang_choice",lang:a(this).val(),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,e,function(e){var n=wpAjax.parseAjaxResponse(e,"ajax-response");a.each(n.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)}})})})});
1
+ !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)})})});
lingotek/lingotek.php CHANGED
@@ -104,7 +104,7 @@ class PLL_Lingotek {
104
  'link' => 'http://www.lingotek.com/wordpress/extra_services',
105
  'new_tab' => true,
106
  'classes' => 'button button-primary',
107
- )
108
  );
109
 
110
  printf( '<p>%s</p>', esc_html__( 'Polylang is now fully integrated with Lingotek, a professional translation management system!', 'polylang' ) );
@@ -158,7 +158,6 @@ class PLL_Lingotek {
158
  array_intersect_key( $links, array_flip( array( 'activate', 'services' ) ) ),
159
  'image04.png'
160
  );
161
-
162
  }
163
 
164
  /**
@@ -166,7 +165,8 @@ class PLL_Lingotek {
166
  *
167
  * @since 1.7.7
168
  */
169
- public function print_css() { ?>
 
170
  <style type="text/css">
171
  .ltk-feature {
172
  text-align: left;
@@ -197,7 +197,7 @@ class PLL_Lingotek {
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;
@@ -221,7 +221,8 @@ class PLL_Lingotek {
221
  padding-bottom: 20px;
222
  }
223
  }
224
- </style><?php
 
225
  }
226
 
227
  /**
@@ -235,34 +236,40 @@ class PLL_Lingotek {
235
  * @param array $links
236
  * @param string $img
237
  */
238
- protected function box( $title, $desc, $list, $links, $img ) {?>
 
239
  <div class="ltk-feature">
240
  <div class="ltk-upper">
241
  <div class="ltk-image">
242
- <img src="<?php echo esc_url( plugins_url( $img, __FILE__ ) );?> " width="220" height="220"/>
243
  </div>
244
  <h3><?php echo esc_html( $title ); ?></h3>
245
- <p class="ltk-desc"><?php echo esc_html( $desc ); ?></p><?php
 
246
  foreach ( $links as $link_details ) {
247
  printf(
248
  '<a class = "%s" href = "%s"%s>%s</a> ',
249
  esc_attr( $link_details['classes'] ),
250
  esc_url( $link_details['link'] ),
251
- empty( $link_details['new_tab'] ) ? '' : ' target = "_blank"',
252
  esc_html( $link_details['label'] )
253
  );
254
- } ?>
 
255
  </div>
256
  <div class="ltk-lower">
257
- <ul><?php
 
258
  foreach ( $list as $item ) {
259
  printf( '<li>%s</li>', esc_html( $item ) );
260
- } ?>
 
261
  </ul>
262
- <a href="http://www.lingotek.com/wordpress" target = "_blank"><?php esc_html_e( 'Learn more...', 'polylang' ) ?></a>
263
  </div>
264
 
265
- </div><?php
 
266
  }
267
 
268
  /**
104
  'link' => 'http://www.lingotek.com/wordpress/extra_services',
105
  'new_tab' => true,
106
  'classes' => 'button button-primary',
107
+ ),
108
  );
109
 
110
  printf( '<p>%s</p>', esc_html__( 'Polylang is now fully integrated with Lingotek, a professional translation management system!', 'polylang' ) );
158
  array_intersect_key( $links, array_flip( array( 'activate', 'services' ) ) ),
159
  'image04.png'
160
  );
 
161
  }
162
 
163
  /**
165
  *
166
  * @since 1.7.7
167
  */
168
+ public function print_css() {
169
+ ?>
170
  <style type="text/css">
171
  .ltk-feature {
172
  text-align: left;
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;
221
  padding-bottom: 20px;
222
  }
223
  }
224
+ </style>
225
+ <?php
226
  }
227
 
228
  /**
236
  * @param array $links
237
  * @param string $img
238
  */
239
+ protected function box( $title, $desc, $list, $links, $img ) {
240
+ ?>
241
  <div class="ltk-feature">
242
  <div class="ltk-upper">
243
  <div class="ltk-image">
244
+ <img src="<?php echo esc_url( plugins_url( $img, __FILE__ ) ); ?> " width="220" height="220"/>
245
  </div>
246
  <h3><?php echo esc_html( $title ); ?></h3>
247
+ <p class="ltk-desc"><?php echo esc_html( $desc ); ?></p>
248
+ <?php
249
  foreach ( $links as $link_details ) {
250
  printf(
251
  '<a class = "%s" href = "%s"%s>%s</a> ',
252
  esc_attr( $link_details['classes'] ),
253
  esc_url( $link_details['link'] ),
254
+ empty( $link_details['new_tab'] ) ? '' : ' target = "_blank"',
255
  esc_html( $link_details['label'] )
256
  );
257
+ }
258
+ ?>
259
  </div>
260
  <div class="ltk-lower">
261
+ <ul>
262
+ <?php
263
  foreach ( $list as $item ) {
264
  printf( '<li>%s</li>', esc_html( $item ) );
265
+ }
266
+ ?>
267
  </ul>
268
+ <a href="http://www.lingotek.com/wordpress" target = "_blank"><?php esc_html_e( 'Learn more...', 'polylang' ); ?></a>
269
  </div>
270
 
271
+ </div>
272
+ <?php
273
  }
274
 
275
  /**
modules/plugins/plugins-compat.php CHANGED
@@ -58,6 +58,12 @@ class PLL_Plugins_Compat {
58
 
59
  // No category base (works for Yoast SEO too)
60
  add_filter( 'get_terms_args', array( $this, 'no_category_base_get_terms_args' ), 5 ); // Before adding cache domain
 
 
 
 
 
 
61
  }
62
 
63
  /**
@@ -99,7 +105,7 @@ class PLL_Plugins_Compat {
99
  load_plugin_textdomain( 'wordpress-importer', false, basename( dirname( $class->getFileName() ) ) . '/languages' );
100
 
101
  $GLOBALS['wp_import'] = new PLL_WP_Import();
102
- register_importer( 'wordpress', 'WordPress', __( 'Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.', 'wordpress-importer' ), array( $GLOBALS['wp_import'], 'dispatch' ) );
103
  }
104
 
105
  /**
@@ -202,13 +208,13 @@ class PLL_Plugins_Compat {
202
  *
203
  * @since 2.1.6
204
  *
205
- * @param array $options
206
- * @param array $titles
207
  * @return array
208
  */
209
  protected function _wpseo_register_strings( $options, $titles ) {
210
  foreach ( $titles as $title ) {
211
- if ( ! empty ( $options[ $title ] ) ) {
212
  pll_register_string( $title, $options[ $title ], 'wordpress-seo' );
213
  }
214
  }
@@ -246,13 +252,13 @@ class PLL_Plugins_Compat {
246
  *
247
  * @since 2.1.6
248
  *
249
- * @param array $options
250
- * @param array $titles
251
  * @return array
252
  */
253
  protected function _wpseo_translate_titles( $options, $titles ) {
254
  foreach ( $titles as $title ) {
255
- if ( ! empty ( $options[ $title ] ) ) {
256
  $options[ $title ] = pll__( $options[ $title ] );
257
  }
258
  }
@@ -297,6 +303,7 @@ class PLL_Plugins_Compat {
297
  * @since 1.6.4
298
  *
299
  * @param string $url
 
300
  * @return $url
301
  */
302
  public function wpseo_home_url( $url, $path ) {
@@ -337,7 +344,7 @@ class PLL_Plugins_Compat {
337
  * @return string
338
  */
339
  public function wpseo_posts_join( $sql, $post_type ) {
340
- return pll_is_translated_post_type( $post_type ) && ( PLL()->options['force_lang'] > 1 || $this->wpseo_get_active_languages() ) ? $sql. PLL()->model->post->join_clause() : $sql;
341
  }
342
 
343
  /**
@@ -432,7 +439,7 @@ class PLL_Plugins_Compat {
432
  // WPSEO already deals with the locale
433
  if ( did_action( 'pll_init' ) && method_exists( $wpseo_og, 'og_tag' ) ) {
434
  foreach ( PLL()->model->get_languages_list() as $language ) {
435
- if ( $language->slug != PLL()->curlang->slug && PLL()->links->get_translation_url( $language ) && $fb_locale = self::get_fb_locale( $language ) ) {
436
  $wpseo_og->og_tag( 'og:locale:alternate', $fb_locale );
437
  }
438
  }
@@ -486,7 +493,7 @@ class PLL_Plugins_Compat {
486
  *
487
  * @since 1.4
488
  *
489
- * @param array $ids featured posts ids
490
  * @return array modified featured posts ids ( include all languages )
491
  */
492
  public function twenty_fourteen_featured_content_ids( $featured_ids ) {
@@ -511,10 +518,12 @@ class PLL_Plugins_Compat {
511
  'lang' => 0, // avoid language filters
512
  'fields' => 'ids',
513
  'numberposts' => Featured_Content::$max_posts,
514
- 'tax_query' => array( array(
515
- 'taxonomy' => 'post_tag',
516
- 'terms' => (int) $tag,
517
- ) ),
 
 
518
  ) );
519
 
520
  $ids = array_merge( $ids, $_ids );
@@ -579,9 +588,15 @@ class PLL_Plugins_Compat {
579
 
580
  /**
581
  * Jetpack
 
582
  * Adapted from the same function in jetpack-3.0.2/3rd-party/wpml.php
583
  *
584
  * @since 1.5.4
 
 
 
 
 
585
  */
586
  public function jetpack_widget_get_top_posts( $posts, $post_ids, $count ) {
587
  foreach ( $posts as $k => $post ) {
@@ -595,10 +610,16 @@ class PLL_Plugins_Compat {
595
 
596
  /**
597
  * Jetpack
 
598
  * Adapted from the same function in jetpack-3.0.2/3rd-party/wpml.php
599
  * Keeps using 'icl_translate' as the function registers the string
600
  *
601
  * @since 1.5.4
 
 
 
 
 
602
  */
603
  public function grunion_contact_form_field_html_filter( $r, $field_label, $id ) {
604
  if ( function_exists( 'icl_translate' ) ) {
@@ -623,10 +644,10 @@ class PLL_Plugins_Compat {
623
  public function jetpack_ogp( $tags ) {
624
  if ( did_action( 'pll_init' ) ) {
625
  foreach ( PLL()->model->get_languages_list() as $language ) {
626
- if ( $language->slug != PLL()->curlang->slug && PLL()->links->get_translation_url( $language ) && $fb_locale = self::get_fb_locale( $language ) ) {
627
  $tags['og:locale:alternate'][] = $fb_locale;
628
  }
629
- if ( $language->slug == PLL()->curlang->slug && $fb_locale = self::get_fb_locale( $language ) ) {
630
  $tags['og:locale'] = $fb_locale;
631
  }
632
  }
@@ -707,6 +728,44 @@ class PLL_Plugins_Compat {
707
  return $args;
708
  }
709
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
710
  /**
711
  * Correspondance between WordPress locales and Facebook locales
712
  * @see https://translate.wordpress.org/
58
 
59
  // No category base (works for Yoast SEO too)
60
  add_filter( 'get_terms_args', array( $this, 'no_category_base_get_terms_args' ), 5 ); // Before adding cache domain
61
+
62
+ // WordPress MU Domain Mapping
63
+ if ( function_exists( 'redirect_to_mapped_domain' ) && ! get_site_option( 'dm_no_primary_domain' ) ) {
64
+ remove_action( 'template_redirect', 'redirect_to_mapped_domain' );
65
+ add_action( 'template_redirect', array( $this, 'dm_redirect_to_mapped_domain' ) );
66
+ }
67
  }
68
 
69
  /**
105
  load_plugin_textdomain( 'wordpress-importer', false, basename( dirname( $class->getFileName() ) ) . '/languages' );
106
 
107
  $GLOBALS['wp_import'] = new PLL_WP_Import();
108
+ register_importer( 'wordpress', 'WordPress', __( 'Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.', 'wordpress-importer' ), array( $GLOBALS['wp_import'], 'dispatch' ) ); // WPCS: spelling ok.
109
  }
110
 
111
  /**
208
  *
209
  * @since 2.1.6
210
  *
211
+ * @param array $options
212
+ * @param array $titles
213
  * @return array
214
  */
215
  protected function _wpseo_register_strings( $options, $titles ) {
216
  foreach ( $titles as $title ) {
217
+ if ( ! empty( $options[ $title ] ) ) {
218
  pll_register_string( $title, $options[ $title ], 'wordpress-seo' );
219
  }
220
  }
252
  *
253
  * @since 2.1.6
254
  *
255
+ * @param array $options
256
+ * @param array $titles
257
  * @return array
258
  */
259
  protected function _wpseo_translate_titles( $options, $titles ) {
260
  foreach ( $titles as $title ) {
261
+ if ( ! empty( $options[ $title ] ) ) {
262
  $options[ $title ] = pll__( $options[ $title ] );
263
  }
264
  }
303
  * @since 1.6.4
304
  *
305
  * @param string $url
306
+ * @param string $path
307
  * @return $url
308
  */
309
  public function wpseo_home_url( $url, $path ) {
344
  * @return string
345
  */
346
  public function wpseo_posts_join( $sql, $post_type ) {
347
+ return pll_is_translated_post_type( $post_type ) && ( PLL()->options['force_lang'] > 1 || $this->wpseo_get_active_languages() ) ? $sql . PLL()->model->post->join_clause() : $sql;
348
  }
349
 
350
  /**
439
  // WPSEO already deals with the locale
440
  if ( did_action( 'pll_init' ) && method_exists( $wpseo_og, 'og_tag' ) ) {
441
  foreach ( PLL()->model->get_languages_list() as $language ) {
442
+ if ( PLL()->curlang->slug !== $language->slug && PLL()->links->get_translation_url( $language ) && $fb_locale = self::get_fb_locale( $language ) ) {
443
  $wpseo_og->og_tag( 'og:locale:alternate', $fb_locale );
444
  }
445
  }
493
  *
494
  * @since 1.4
495
  *
496
+ * @param array $featured_ids featured posts ids
497
  * @return array modified featured posts ids ( include all languages )
498
  */
499
  public function twenty_fourteen_featured_content_ids( $featured_ids ) {
518
  'lang' => 0, // avoid language filters
519
  'fields' => 'ids',
520
  'numberposts' => Featured_Content::$max_posts,
521
+ 'tax_query' => array(
522
+ array(
523
+ 'taxonomy' => 'post_tag',
524
+ 'terms' => (int) $tag,
525
+ ),
526
+ ),
527
  ) );
528
 
529
  $ids = array_merge( $ids, $_ids );
588
 
589
  /**
590
  * Jetpack
591
+ * Filter the Top Posts and Pages by language.
592
  * Adapted from the same function in jetpack-3.0.2/3rd-party/wpml.php
593
  *
594
  * @since 1.5.4
595
+ *
596
+ * @param array $posts Array of the most popular posts.
597
+ * @param array $post_ids Array of Post IDs.
598
+ * @param string $count Number of Top Posts we want to display.
599
+ * @return array
600
  */
601
  public function jetpack_widget_get_top_posts( $posts, $post_ids, $count ) {
602
  foreach ( $posts as $k => $post ) {
610
 
611
  /**
612
  * Jetpack
613
+ * Filter the HTML of the Contact Form and output the one requested by language.
614
  * Adapted from the same function in jetpack-3.0.2/3rd-party/wpml.php
615
  * Keeps using 'icl_translate' as the function registers the string
616
  *
617
  * @since 1.5.4
618
+ *
619
+ * @param string $r Contact Form HTML output.
620
+ * @param string $field_label Field label.
621
+ * @param int|null $id Post ID.
622
+ * @return string
623
  */
624
  public function grunion_contact_form_field_html_filter( $r, $field_label, $id ) {
625
  if ( function_exists( 'icl_translate' ) ) {
644
  public function jetpack_ogp( $tags ) {
645
  if ( did_action( 'pll_init' ) ) {
646
  foreach ( PLL()->model->get_languages_list() as $language ) {
647
+ if ( PLL()->curlang->slug !== $language->slug && PLL()->links->get_translation_url( $language ) && $fb_locale = self::get_fb_locale( $language ) ) {
648
  $tags['og:locale:alternate'][] = $fb_locale;
649
  }
650
+ if ( PLL()->curlang->slug === $language->slug && $fb_locale = self::get_fb_locale( $language ) ) {
651
  $tags['og:locale'] = $fb_locale;
652
  }
653
  }
728
  return $args;
729
  }
730
 
731
+ /**
732
+ * WordPress MU Domain Mapping
733
+ * Fix primary domain check which forces only one domain per blog
734
+ * Accept only known domains/subdomains for the current blog
735
+ *
736
+ * @since 2.2
737
+ */
738
+ public function dm_redirect_to_mapped_domain() {
739
+ // Don't redirect the main site
740
+ if ( is_main_site() ) {
741
+ return;
742
+ }
743
+
744
+ // Don't redirect post previews
745
+ if ( isset( $_GET['preview'] ) && 'true' === $_GET['preview'] ) {
746
+ return;
747
+ }
748
+
749
+ // Don't redirect theme customizer
750
+ if ( isset( $_POST['customize'] ) && isset( $_POST['theme'] ) && 'on' === $_POST['customize'] ) {
751
+ return;
752
+ }
753
+
754
+ // If we can't associate the requested domain to a language, redirect to the default domain
755
+ $options = get_option( 'polylang' );
756
+ if ( $options['force_lang'] > 1 ) {
757
+ $hosts = PLL()->links_model->get_hosts();
758
+ $lang = array_search( $_SERVER['HTTP_HOST'], $hosts );
759
+
760
+ if ( empty( $lang ) ) {
761
+ $status = get_site_option( 'dm_301_redirect' ) ? '301' : '302'; // Honor status redirect option
762
+ $redirect = ( is_ssl() ? 'https://' : 'http://' ) . $hosts[ $options['default_lang'] ] . $_SERVER['REQUEST_URI'];
763
+ wp_redirect( $redirect, $status );
764
+ exit;
765
+ }
766
+ }
767
+ }
768
+
769
  /**
770
  * Correspondance between WordPress locales and Facebook locales
771
  * @see https://translate.wordpress.org/
modules/plugins/wp-import.php CHANGED
@@ -178,8 +178,8 @@ class PLL_WP_Import extends WP_Import {
178
 
179
  if ( ! empty( $u ) ) {
180
  $wpdb->query( "UPDATE $wpdb->term_taxonomy
181
- SET description = ( CASE term_id " . implode( ' ', $u['case'] ) . " END )
182
- WHERE term_id IN ( " . implode( ',', $u['in'] ) . " )" );
183
  }
184
  }
185
  }
178
 
179
  if ( ! empty( $u ) ) {
180
  $wpdb->query( "UPDATE $wpdb->term_taxonomy
181
+ SET description = ( CASE term_id " . implode( ' ', $u['case'] ) . ' END )
182
+ WHERE term_id IN ( ' . implode( ',', $u['in'] ) . ' )' );
183
  }
184
  }
185
  }
modules/share-slug/settings-share-slug.php CHANGED
@@ -18,7 +18,7 @@ class PLL_Settings_Share_Slug extends PLL_Settings_Module {
18
  parent::__construct( $polylang, array(
19
  'module' => 'share-slugs',
20
  'title' => __( 'Share slugs', 'polylang' ),
21
- 'description' => __( 'Allows to share the same url slug accross languages for posts and terms.', 'polylang' ),
22
  ) );
23
 
24
  if ( class_exists( 'PLL_Share_Post_Slug', true ) && get_option( 'permalink_structure' ) ) {
@@ -75,6 +75,7 @@ class PLL_Settings_Share_Slug extends PLL_Settings_Module {
75
  } );
76
  } )( jQuery );
77
  // ]]>
78
- </script><?php
 
79
  }
80
  }
18
  parent::__construct( $polylang, array(
19
  'module' => 'share-slugs',
20
  'title' => __( 'Share slugs', 'polylang' ),
21
+ 'description' => __( 'Allows to share the same url slug across languages for posts and terms.', 'polylang' ),
22
  ) );
23
 
24
  if ( class_exists( 'PLL_Share_Post_Slug', true ) && get_option( 'permalink_structure' ) ) {
75
  } );
76
  } )( jQuery );
77
  // ]]>
78
+ </script>
79
+ <?php
80
  }
81
  }
modules/sync/admin-sync.php CHANGED
@@ -126,7 +126,7 @@ class PLL_Admin_Sync {
126
  * @param int $from id of the post from which we copy informations
127
  * @param int $to id of the post to which we paste informations
128
  * @param string $lang language slug
129
- * @param bool $sync true if it is synchronization, false if it is a copy, defaults to false
130
  */
131
  public function copy_taxonomies( $from, $to, $lang, $sync = false ) {
132
  // Get taxonomies to sync for this post type
@@ -291,8 +291,8 @@ class PLL_Admin_Sync {
291
  $tr_arr = empty( $postarr ) ? array() : $postarr;
292
 
293
  if ( isset( $GLOBALS['post_type'] ) ) {
294
- $post_type = $GLOBALS['post_type'];
295
- } elseif ( isset( $_REQUEST['post_type'] ) ){
296
  $post_type = $_REQUEST['post_type']; // 2nd case for quick edit
297
  }
298
 
@@ -325,8 +325,15 @@ class PLL_Admin_Sync {
325
  * @param array $translations translations of the term
326
  */
327
  public function pll_save_term( $term_id, $taxonomy, $translations ) {
 
 
 
 
 
 
 
328
  // Check if the taxonomy is synchronized
329
- if ( ! $this->model->is_translated_taxonomy( $taxonomy ) || ! in_array( $taxonomy, $this->get_taxonomies_to_copy( true ) ) ) {
330
  return;
331
  }
332
 
@@ -337,12 +344,14 @@ class PLL_Admin_Sync {
337
  'post_type' => 'any',
338
  'post_status' => 'any',
339
  'fields' => 'ids',
340
- 'tax_query' => array( array(
341
- 'taxonomy' => $taxonomy,
342
- 'field' => 'id',
343
- 'terms' => array_merge( array( $term_id ), array_values( $translations ) ),
344
- 'include_children' => false,
345
- ) ),
 
 
346
  ) );
347
 
348
  // Associate translated term to translated post
@@ -392,4 +401,42 @@ class PLL_Admin_Sync {
392
  public function edit_attachment( $post_id ) {
393
  $this->pll_save_post( $post_id, get_post( $post_id ), $this->model->post->get_translations( $post_id ) );
394
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
  }
126
  * @param int $from id of the post from which we copy informations
127
  * @param int $to id of the post to which we paste informations
128
  * @param string $lang language slug
129
+ * @param bool $sync true if it is synchronization, false if it is a copy, defaults to false
130
  */
131
  public function copy_taxonomies( $from, $to, $lang, $sync = false ) {
132
  // Get taxonomies to sync for this post type
291
  $tr_arr = empty( $postarr ) ? array() : $postarr;
292
 
293
  if ( isset( $GLOBALS['post_type'] ) ) {
294
+ $post_type = $GLOBALS['post_type'];
295
+ } elseif ( isset( $_REQUEST['post_type'] ) ) {
296
  $post_type = $_REQUEST['post_type']; // 2nd case for quick edit
297
  }
298
 
325
  * @param array $translations translations of the term
326
  */
327
  public function pll_save_term( $term_id, $taxonomy, $translations ) {
328
+ // Sync term metas
329
+ foreach ( $translations as $lang => $tr_id ) {
330
+ if ( $tr_id && $tr_id !== $term_id ) {
331
+ $this->copy_term_metas( $term_id, $tr_id, $lang, true );
332
+ }
333
+ }
334
+
335
  // Check if the taxonomy is synchronized
336
+ if ( ! in_array( $taxonomy, $this->get_taxonomies_to_copy( true ) ) ) {
337
  return;
338
  }
339
 
344
  'post_type' => 'any',
345
  'post_status' => 'any',
346
  'fields' => 'ids',
347
+ 'tax_query' => array(
348
+ array(
349
+ 'taxonomy' => $taxonomy,
350
+ 'field' => 'id',
351
+ 'terms' => array_merge( array( $term_id ), array_values( $translations ) ),
352
+ 'include_children' => false,
353
+ ),
354
+ ),
355
  ) );
356
 
357
  // Associate translated term to translated post
401
  public function edit_attachment( $post_id ) {
402
  $this->pll_save_post( $post_id, get_post( $post_id ), $this->model->post->get_translations( $post_id ) );
403
  }
404
+
405
+ /**
406
+ * Copy or synchronize term metas (custom fields)
407
+ *
408
+ * @since 2.2
409
+ *
410
+ * @param int $from id of the term from which we copy informations
411
+ * @param int $to id of the term to which we paste informations
412
+ * @param string $lang language slug
413
+ * @param bool $sync true if it is synchronization, false if it is a copy, defaults to false
414
+ */
415
+ public function copy_term_metas( $from, $to, $lang, $sync = false ) {
416
+ $metas = get_term_meta( $from );
417
+
418
+ /**
419
+ * Filter the term metas to copy or synchronize
420
+ *
421
+ * @since 2.2
422
+ *
423
+ * @param array $keys list of term meta names
424
+ * @param bool $sync true if it is synchronization, false if it is a copy
425
+ * @param int $from id of the term from which we copy informations
426
+ * @param int $to id of the term to which we paste informations
427
+ * @param string $lang language slug
428
+ */
429
+ $keys = array_unique( apply_filters( 'pll_copy_term_metas', array(), $sync, $from, $to, $lang ) );
430
+
431
+ // And now copy / synchronize
432
+ foreach ( $keys as $key ) {
433
+ delete_term_meta( $to, $key ); // The synchronization process of multiple values term metas is easier if we delete all metas first
434
+ if ( isset( $metas[ $key ] ) ) {
435
+ foreach ( $metas[ $key ] as $value ) {
436
+ $value = maybe_unserialize( $value );
437
+ add_term_meta( $to, $key, $value );
438
+ }
439
+ }
440
+ }
441
+ }
442
  }
modules/sync/settings-sync.php CHANGED
@@ -37,8 +37,10 @@ class PLL_Settings_Sync extends PLL_Settings_Module {
37
  *
38
  * @since 1.8
39
  */
40
- protected function form() {?>
41
- <ul class="pll-inline-block-list"><?php
 
 
42
  foreach ( self::list_metas_to_sync() as $key => $str ) {
43
  printf(
44
  '<li><label><input name="sync[%s]" type="checkbox" value="1" %s /> %s</label></li>',
@@ -46,8 +48,10 @@ class PLL_Settings_Sync extends PLL_Settings_Module {
46
  in_array( $key, $this->options['sync'] ) ? 'checked="checked"' : '',
47
  esc_html( $str )
48
  );
49
- } ?>
50
- </ul><?php
 
 
51
  }
52
 
53
  /**
37
  *
38
  * @since 1.8
39
  */
40
+ protected function form() {
41
+ ?>
42
+ <ul class="pll-inline-block-list">
43
+ <?php
44
  foreach ( self::list_metas_to_sync() as $key => $str ) {
45
  printf(
46
  '<li><label><input name="sync[%s]" type="checkbox" value="1" %s /> %s</label></li>',
48
  in_array( $key, $this->options['sync'] ) ? 'checked="checked"' : '',
49
  esc_html( $str )
50
  );
51
+ }
52
+ ?>
53
+ </ul>
54
+ <?php
55
  }
56
 
57
  /**
modules/wpml/wpml-api.php CHANGED
@@ -18,7 +18,7 @@ class PLL_WPML_API {
18
  // Site Wide Language informations
19
 
20
  add_filter( 'wpml_active_languages', array( $this, 'wpml_active_languages' ), 10, 2 );
21
- // wpml_display_language_names => not implemented
22
  // wpml_translated_language_name => not applicable
23
  add_filter( 'wpml_current_language', 'pll_current_language', 10, 0 );
24
  add_filter( 'wpml_default_language', 'pll_default_language', 10, 0 );
@@ -45,9 +45,9 @@ class PLL_WPML_API {
45
  add_filter( 'wpml_translate_single_string', array( $this, 'wpml_translate_single_string' ), 10, 4 );
46
  // wpml_translate_string => not applicable
47
  // wpml_unfiltered_admin_string => not implemented
48
- add_filter( 'wpml_permalink', array( PLL()->links_model, 'switch_language_in_link' ), 10, 2 );
49
  // wpml_elements_without_translations => not implemented
50
- // wpml_get_translated_slug => not implemented
51
 
52
  // Finding the Translation State of Content
53
 
@@ -83,6 +83,7 @@ class PLL_WPML_API {
83
  // wpml_loaded => not applicable
84
  // wpml_st_loaded => not applicable
85
  // wpml_tm_loaded => not applicable
 
86
  }
87
 
88
  /**
@@ -90,14 +91,31 @@ class PLL_WPML_API {
90
  *
91
  * @since 2.0
92
  *
93
- * @param mixed $null not used
94
- * @param array| string $args see arguments of icl_get_languages()
95
- * @return array array of arrays per language
96
  */
97
  public function wpml_active_languages( $null, $args = '' ) {
98
  return icl_get_languages( $args );
99
  }
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  /**
102
  * Returns an HTML hidden input field with name=”lang” and as value the current language
103
  *
@@ -115,8 +133,8 @@ class PLL_WPML_API {
115
  *
116
  * @since 2.0
117
  *
118
- * @param mixed $null not used
119
- * @param string $slug language code
120
  * @return bool
121
  */
122
  public function wpml_language_is_active( $null, $slug ) {
@@ -129,7 +147,7 @@ class PLL_WPML_API {
129
  *
130
  * @since 2.0
131
  *
132
- * @param mixed $null not used
133
  * @return bool
134
  */
135
  public function wpml_is_rtl( $null ) {
@@ -142,7 +160,7 @@ class PLL_WPML_API {
142
  * @since 2.0
143
  *
144
  * @param mixed $language_code
145
- * @param array $args an array with two keys element_id => post_id or term_taxonomy_id, element_type => post type or taxonomy
146
  * @return string
147
  */
148
  public function wpml_element_language_code( $language_code, $args ) {
@@ -160,25 +178,65 @@ class PLL_WPML_API {
160
  *
161
  * @since 2.0
162
  *
163
- * @param string $string the string's original value
164
- * @param string $context the string's registered context
165
- * @param string $name the string's registered name
166
- * @param null|string $lang optional, return the translation in this language, defaults to current language
167
- * @return string the translated string
168
  */
169
  public function wpml_translate_single_string( $string, $context, $name, $lang = null ) {
170
  $has_translation = null; // Passed by reference
171
  return icl_translate( $context, $name, $string, false, $has_translation, $lang );
172
  }
173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  /**
175
  * Find out whether a post type or a taxonomy term is translated
176
  *
177
  * @since 2.0
178
  *
179
  * @param mixed $null
180
- * @param int $id post_id or term_id
181
- * @param string $type post type or taxonomy
182
  * @return bool
183
  */
184
  public function wpml_element_has_translations( $null, $id, $type ) {
18
  // Site Wide Language informations
19
 
20
  add_filter( 'wpml_active_languages', array( $this, 'wpml_active_languages' ), 10, 2 );
21
+ add_filter( 'wpml_display_language_names', array( $this, 'wpml_display_language_names' ), 10, 5 );
22
  // wpml_translated_language_name => not applicable
23
  add_filter( 'wpml_current_language', 'pll_current_language', 10, 0 );
24
  add_filter( 'wpml_default_language', 'pll_default_language', 10, 0 );
45
  add_filter( 'wpml_translate_single_string', array( $this, 'wpml_translate_single_string' ), 10, 4 );
46
  // wpml_translate_string => not applicable
47
  // wpml_unfiltered_admin_string => not implemented
48
+ add_filter( 'wpml_permalink', array( $this, 'wpml_permalink' ), 10, 2 );
49
  // wpml_elements_without_translations => not implemented
50
+ add_filter( 'wpml_get_translated_slug', array( $this, 'wpml_get_translated_slug' ), 10, 3 );
51
 
52
  // Finding the Translation State of Content
53
 
83
  // wpml_loaded => not applicable
84
  // wpml_st_loaded => not applicable
85
  // wpml_tm_loaded => not applicable
86
+ // wpml_hide_management_column (3.4.1) => not applicable
87
  }
88
 
89
  /**
91
  *
92
  * @since 2.0
93
  *
94
+ * @param mixed $null Not used
95
+ * @param array| string $args See arguments of icl_get_languages()
96
+ * @return array Array of arrays per language
97
  */
98
  public function wpml_active_languages( $null, $args = '' ) {
99
  return icl_get_languages( $args );
100
  }
101
 
102
+ /**
103
+ * In WPML, get a language's native and translated name for display in a custom language switcher
104
+ * Since Polylang does not implement the translated name, always returns only the native name
105
+ *
106
+ * @since 2.2
107
+ *
108
+ * @param mixed $null Not used.
109
+ * @param string $native_name The language native name.
110
+ * @param string|bool $translated_name The language translated name. Not used.
111
+ * @param bool $native_hidden Whether to hide the language native name or not. Not used.
112
+ * @param bool $translated_hidden Whether to hide the language translated name or not. Not used.
113
+ * @return string
114
+ */
115
+ public function wpml_display_language_names( $null, $native_name, $translated_name = false, $native_hidden = false, $translated_hidden = false ) {
116
+ return $native_name;
117
+ }
118
+
119
  /**
120
  * Returns an HTML hidden input field with name=”lang” and as value the current language
121
  *
133
  *
134
  * @since 2.0
135
  *
136
+ * @param mixed $null Not used
137
+ * @param string $slug Language code
138
  * @return bool
139
  */
140
  public function wpml_language_is_active( $null, $slug ) {
147
  *
148
  * @since 2.0
149
  *
150
+ * @param mixed $null Not used
151
  * @return bool
152
  */
153
  public function wpml_is_rtl( $null ) {
160
  * @since 2.0
161
  *
162
  * @param mixed $language_code
163
+ * @param array $args An array with two keys element_id => post_id or term_taxonomy_id, element_type => post type or taxonomy
164
  * @return string
165
  */
166
  public function wpml_element_language_code( $language_code, $args ) {
178
  *
179
  * @since 2.0
180
  *
181
+ * @param string $string The string's original value
182
+ * @param string $context The string's registered context
183
+ * @param string $name The string's registered name
184
+ * @param null|string $lang Optional, return the translation in this language, defaults to current language
185
+ * @return string The translated string
186
  */
187
  public function wpml_translate_single_string( $string, $context, $name, $lang = null ) {
188
  $has_translation = null; // Passed by reference
189
  return icl_translate( $context, $name, $string, false, $has_translation, $lang );
190
  }
191
 
192
+ /**
193
+ * Converts a permalink to a language specific permalink
194
+ *
195
+ * @since 2.2
196
+ *
197
+ * @param string $url The url to filter
198
+ * @param null|string $lang Langage code, optional, defaults to the current language
199
+ * @return string
200
+ */
201
+ public function wpml_permalink( $url, $lang = '' ) {
202
+ $lang = PLL()->model->get_language( $lang );
203
+
204
+ if ( empty( $lang ) && ! empty( PLL()->curlang ) ) {
205
+ $lang = PLL()->curlang;
206
+ }
207
+
208
+ return empty( $lang ) ? $url : PLL()->links_model->switch_language_in_link( $url, $lang );
209
+ }
210
+
211
+ /**
212
+ * Translates a post type slug
213
+ *
214
+ * @since 2.2
215
+ *
216
+ * @param string $slug Post type slug
217
+ * @param string $post_type Post type name
218
+ * @param string $lang Optional language code (defaults to current language)
219
+ * @return string
220
+ */
221
+ public function wpml_get_translated_slug( $slug, $post_type, $lang = null ) {
222
+ if ( isset( PLL()->translate_slugs ) ) {
223
+ if ( empty( $lang ) ) {
224
+ $lang = pll_current_language();
225
+ }
226
+
227
+ $slug = PLL()->translate_slugs->slugs_model->get_translated_slug( $post_type, $lang );
228
+ }
229
+ return $slug;
230
+ }
231
+
232
  /**
233
  * Find out whether a post type or a taxonomy term is translated
234
  *
235
  * @since 2.0
236
  *
237
  * @param mixed $null
238
+ * @param int $id The post_id or term_id
239
+ * @param string $type The post type or taxonomy
240
  * @return bool
241
  */
242
  public function wpml_element_has_translations( $null, $id, $type ) {
modules/wpml/wpml-compat.php CHANGED
@@ -25,6 +25,7 @@ class PLL_WPML_Compat {
25
  self::$strings = get_option( 'polylang_wpml_strings', array() );
26
 
27
  add_action( 'pll_language_defined', array( $this, 'define_constants' ) );
 
28
  add_filter( 'pll_get_strings', array( $this, 'get_strings' ) );
29
  }
30
 
25
  self::$strings = get_option( 'polylang_wpml_strings', array() );
26
 
27
  add_action( 'pll_language_defined', array( $this, 'define_constants' ) );
28
+ add_action( 'pll_no_language_defined', array( $this, 'define_constants' ) );
29
  add_filter( 'pll_get_strings', array( $this, 'get_strings' ) );
30
  }
31
 
modules/wpml/wpml-config.php CHANGED
@@ -44,16 +44,6 @@ class PLL_WPML_Config {
44
  public function init() {
45
  $this->xmls = array();
46
 
47
- // Theme
48
- if ( file_exists( $file = ( $template = get_template_directory() ) . '/wpml-config.xml' ) && false !== $xml = simplexml_load_file( $file ) ) {
49
- $this->xmls[ get_template() ] = $xml;
50
- }
51
-
52
- // Child theme
53
- if ( ( $stylesheet = get_stylesheet_directory() ) !== $template && file_exists( $file = $stylesheet . '/wpml-config.xml' ) && false !== $xml = simplexml_load_file( $file ) ) {
54
- $this->xmls[ get_stylesheet() ] = $xml;
55
- }
56
-
57
  // Plugins
58
  // Don't forget sitewide active plugins thanks to Reactorshop http://wordpress.org/support/topic/polylang-and-yoast-seo-plugin/page/2?replies=38#post-4801829
59
  $plugins = ( is_multisite() && $sitewide_plugins = get_site_option( 'active_sitewide_plugins' ) ) && is_array( $sitewide_plugins ) ? array_keys( $sitewide_plugins ) : array();
@@ -65,6 +55,16 @@ class PLL_WPML_Config {
65
  }
66
  }
67
 
 
 
 
 
 
 
 
 
 
 
68
  // Custom
69
  if ( file_exists( $file = PLL_LOCAL_DIR . '/wpml-config.xml' ) && false !== $xml = simplexml_load_file( $file ) ) {
70
  $this->xmls['Polylang'] = $xml;
@@ -103,7 +103,7 @@ class PLL_WPML_Config {
103
  foreach ( $this->xmls as $xml ) {
104
  foreach ( $xml->xpath( 'custom-fields/custom-field' ) as $cf ) {
105
  $attributes = $cf->attributes();
106
- if ( 'copy' == $attributes['action'] || ( ! $sync && 'translate' == $attributes['action'] ) ) {
107
  $metas[] = (string) $cf;
108
  } else {
109
  $metas = array_diff( $metas, array( (string) $cf ) );
@@ -164,7 +164,7 @@ class PLL_WPML_Config {
164
  *
165
  * @since 1.0
166
  *
167
- * @param array|string either a string to translate or a list of strings to translate
168
  * @return array|string translated string(s)
169
  */
170
  public function translate_strings( $value ) {
@@ -187,7 +187,11 @@ class PLL_WPML_Config {
187
  foreach ( $children as $child ) {
188
  $attributes = $child->attributes();
189
  $name = (string) $attributes['name'];
190
- if ( isset( $options[ $name ] ) ) {
 
 
 
 
191
  $this->register_string_recursive( $context, $options[ $name ], $child );
192
  }
193
  }
@@ -197,6 +201,25 @@ class PLL_WPML_Config {
197
  }
198
  }
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  /**
201
  * Recursively translates strings for a serialized option
202
  *
@@ -212,7 +235,11 @@ class PLL_WPML_Config {
212
  foreach ( $children as $child ) {
213
  $attributes = $child->attributes();
214
  $name = (string) $attributes['name'];
215
- if ( isset( $values[ $name ] ) ) {
 
 
 
 
216
  $values[ $name ] = $this->translate_strings_recursive( $values[ $name ], $child );
217
  }
218
  }
@@ -221,4 +248,24 @@ class PLL_WPML_Config {
221
  }
222
  return $values;
223
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  }
44
  public function init() {
45
  $this->xmls = array();
46
 
 
 
 
 
 
 
 
 
 
 
47
  // Plugins
48
  // Don't forget sitewide active plugins thanks to Reactorshop http://wordpress.org/support/topic/polylang-and-yoast-seo-plugin/page/2?replies=38#post-4801829
49
  $plugins = ( is_multisite() && $sitewide_plugins = get_site_option( 'active_sitewide_plugins' ) ) && is_array( $sitewide_plugins ) ? array_keys( $sitewide_plugins ) : array();
55
  }
56
  }
57
 
58
+ // Theme
59
+ if ( file_exists( $file = ( $template = get_template_directory() ) . '/wpml-config.xml' ) && false !== $xml = simplexml_load_file( $file ) ) {
60
+ $this->xmls[ get_template() ] = $xml;
61
+ }
62
+
63
+ // Child theme
64
+ if ( ( $stylesheet = get_stylesheet_directory() ) !== $template && file_exists( $file = $stylesheet . '/wpml-config.xml' ) && false !== $xml = simplexml_load_file( $file ) ) {
65
+ $this->xmls[ get_stylesheet() ] = $xml;
66
+ }
67
+
68
  // Custom
69
  if ( file_exists( $file = PLL_LOCAL_DIR . '/wpml-config.xml' ) && false !== $xml = simplexml_load_file( $file ) ) {
70
  $this->xmls['Polylang'] = $xml;
103
  foreach ( $this->xmls as $xml ) {
104
  foreach ( $xml->xpath( 'custom-fields/custom-field' ) as $cf ) {
105
  $attributes = $cf->attributes();
106
+ if ( 'copy' == $attributes['action'] || ( ! $sync && in_array( $attributes['action'], array( 'translate', 'copy-once' ) ) ) ) {
107
  $metas[] = (string) $cf;
108
  } else {
109
  $metas = array_diff( $metas, array( (string) $cf ) );
164
  *
165
  * @since 1.0
166
  *
167
+ * @param array|string $value Either a string to translate or a list of strings to translate
168
  * @return array|string translated string(s)
169
  */
170
  public function translate_strings( $value ) {
187
  foreach ( $children as $child ) {
188
  $attributes = $child->attributes();
189
  $name = (string) $attributes['name'];
190
+ if ( '*' === $name && is_array( $options ) ) {
191
+ foreach ( $options as $n => $option ) {
192
+ $this->register_wildcard_options_recursive( $context, $option, $n );
193
+ }
194
+ } elseif ( isset( $options[ $name ] ) ) {
195
  $this->register_string_recursive( $context, $options[ $name ], $child );
196
  }
197
  }
201
  }
202
  }
203
 
204
+ /**
205
+ * Recursively registers strings with a wildcard
206
+ *
207
+ * @since 2.1
208
+ *
209
+ * @param string $context the group in which the strings will be registered
210
+ * @param array $options
211
+ * @param string $name Option name
212
+ */
213
+ protected function register_wildcard_options_recursive( $context, $options, $name ) {
214
+ if ( is_array( $options ) ) {
215
+ foreach ( $options as $n => $option ) {
216
+ $this->register_wildcard_options_recursive( $context, $option, $n );
217
+ }
218
+ } else {
219
+ pll_register_string( $name, $options, $context );
220
+ }
221
+ }
222
+
223
  /**
224
  * Recursively translates strings for a serialized option
225
  *
235
  foreach ( $children as $child ) {
236
  $attributes = $child->attributes();
237
  $name = (string) $attributes['name'];
238
+ if ( '*' === $name && is_array( $values ) ) {
239
+ foreach ( $values as $n => $v ) {
240
+ $values[ $n ] = $this->translate_wildcard_options_recursive( $v, $n );
241
+ }
242
+ } elseif ( isset( $values[ $name ] ) ) {
243
  $values[ $name ] = $this->translate_strings_recursive( $values[ $name ], $child );
244
  }
245
  }
248
  }
249
  return $values;
250
  }
251
+
252
+ /**
253
+ * Recursively translates strings registered by a wildcard
254
+ *
255
+ * @since 2.1
256
+ *
257
+ * @param array|string $options Either a string to translate or a list of strings to translate
258
+ * @param string $name Option name
259
+ * @return array|string Translated string(s)
260
+ */
261
+ protected function translate_wildcard_options_recursive( $options, $name ) {
262
+ if ( is_array( $options ) ) {
263
+ foreach ( $options as $n => $option ) {
264
+ $options[ $n ] = $this->translate_wildcard_options_recursive( $option, $n );
265
+ }
266
+ } else {
267
+ $options = pll__( $options );
268
+ }
269
+ return $options;
270
+ }
271
  }
modules/wpml/wpml-legacy-api.php CHANGED
@@ -6,47 +6,47 @@
6
  * But a lot of 3rd party plugins / themes are still using these functions
7
  */
8
 
9
- /**
10
- * Link to the home page in the active language
11
- *
12
- * @since 0.9.4
13
- *
14
- * @return string
15
- */
16
  if ( ! function_exists( 'icl_get_home_url' ) ) {
 
 
 
 
 
 
 
17
  function icl_get_home_url() {
18
  return pll_home_url();
19
  }
20
  }
21
 
22
- /**
23
- * Used for building custom language selectors
24
- * available only on frontend
25
- *
26
- * list of paramaters accepted in $args
27
- *
28
- * skip_missing => wether to skip missing translation or not, 0 or 1, defaults to 0
29
- * orderby => 'id', 'code', 'name', defaults to 'id'
30
- * order => 'ASC' or 'DESC', defaults to 'ASC'
31
- * link_empty_to => link to use when the translation is missing {$lang} is replaced by the language code
32
- *
33
- * list of parameters returned per language:
34
- *
35
- * id => the language id
36
- * active => wether this is the active language or no, 0 or 1
37
- * native_name => the language name
38
- * missing => wether the translation is missing or not, 0 or 1
39
- * translated_name => empty, does not exist in Polylang
40
- * language_code => the language code ( slug )
41
- * country_flag_url => the url of the flag
42
- * url => the url of the translation
43
- *
44
- * @since 1.0
45
- *
46
- * @param string|array $args optional
47
- * @return array array of arrays per language
48
- */
49
  if ( ! function_exists( 'icl_get_languages' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  function icl_get_languages( $args = '' ) {
51
  $args = wp_parse_args( $args, array( 'skip_missing' => 0, 'orderby' => 'id', 'order' => 'ASC' ) );
52
  $orderby = ( isset( $args['orderby'] ) && 'code' == $args['orderby'] ) ? 'slug' : ( isset( $args['orderby'] ) && 'name' == $args['orderby'] ? 'name' : 'id' );
@@ -78,26 +78,30 @@ if ( ! function_exists( 'icl_get_languages' ) ) {
78
  str_replace( '{$lang}', $lang->slug, $args['link_empty_to'] ) ),
79
  );
80
  }
 
 
 
 
81
  return $arr;
82
  }
83
  }
84
 
85
- /**
86
- * Used for creating language dependent links in themes
87
- *
88
- * @since 1.0
89
- * @since 2.0 add support for arguments 6 and 7
90
- *
91
- * @param int $id object id
92
- * @param string $type optional, post type or taxonomy name of the object, defaults to 'post'
93
- * @param string $text optional, the link text. If not specified will produce the name of the element in the current language
94
- * @param array $args optional, an array of arguments to add to the link, defaults to empty
95
- * @param string $anchor optional, the anchor to add to the link, defaults to empty
96
- * @param bool $echo optional, whether to echo the link, defaults to true
97
- * @param bool $return_original_if_missing optional, whether to return a value if the translation is missing
98
- * @return string a language dependent link
99
- */
100
  if ( ! function_exists( 'icl_link_to_element' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  function icl_link_to_element( $id, $type = 'post', $text = '', $args = array(), $anchor = '', $echo = true, $return_original_if_missing = true ) {
102
  if ( 'tag' == $type ) {
103
  $type = 'post_tag';
@@ -144,18 +148,18 @@ if ( ! function_exists( 'icl_link_to_element' ) ) {
144
  }
145
  }
146
 
147
- /**
148
- * Used for calculating the IDs of objects (usually categories) in the current language
149
- *
150
- * @since 0.9.5
151
- *
152
- * @param int $id object id
153
- * @param string $type optional, post type or taxonomy name of the object, defaults to 'post'
154
- * @param bool $return_original_if_missing optional, true if Polylang should return the original id if the translation is missing, defaults to false
155
- * @param string $lang optional, language code, defaults to current language
156
- * @return int|null the object id of the translation, null if the translation is missing and $return_original_if_missing set to false
157
- */
158
  if ( ! function_exists( 'icl_object_id' ) ) {
 
 
 
 
 
 
 
 
 
 
 
159
  function icl_object_id( $id, $type = 'post', $return_original_if_missing = false, $lang = false ) {
160
  $pll_type = ( 'post' === $type || pll_is_translated_post_type( $type ) ) ? 'post' : ( 'term' === $type || pll_is_translated_taxonomy( $type ) ? 'term' : false );
161
  return $pll_type && ( $lang = $lang ? $lang : pll_current_language() ) && ( $tr_id = PLL()->model->$pll_type->get_translation( $id, $lang ) ) ? $tr_id :
@@ -163,18 +167,18 @@ if ( ! function_exists( 'icl_object_id' ) ) {
163
  }
164
  }
165
 
166
- /**
167
- * Undocumented function used by the theme Maya
168
- * returns the post language
169
- * @see original WPML code at https://wpml.org/forums/topic/canonical-urls-for-wpml-duplicated-posts/#post-52198
170
- *
171
- * @since 1.8
172
- *
173
- * @param null $empty optional, not used
174
- * @param int $post_id optional, post id, defaults to current post
175
- * @return array
176
- */
177
  if ( ! function_exists( 'wpml_get_language_information' ) ) {
 
 
 
 
 
 
 
 
 
 
 
178
  function wpml_get_language_information( $empty = null, $post_id = null ) {
179
  if ( empty( $post_id ) ) {
180
  $post_id = get_the_ID();
@@ -187,79 +191,79 @@ if ( ! function_exists( 'wpml_get_language_information' ) ) {
187
  'text_direction' => (bool) $lang->is_rtl,
188
  'display_name' => $lang->name, // Seems to be the post language name displayed in the current language, not a feature in Polylang
189
  'native_name' => $lang->name,
190
- 'different_language' => $lang->slug != pll_current_language(),
191
  );
192
  }
193
  }
194
 
195
- /**
196
- * Registers a string for translation in the "strings translation" panel
197
- *
198
- * @since 0.9.3
199
- *
200
- * @param string $context the group in which the string is registered, defaults to 'polylang'
201
- * @param string $name a unique name for the string
202
- * @param string $string the string to register
203
- * @param bool $allow_empty_value not used
204
- * @param string $source_lang not used by Polylang
205
- */
206
  if ( ! function_exists( 'icl_register_string' ) ) {
 
 
 
 
 
 
 
 
 
 
 
207
  function icl_register_string( $context, $name, $string, $allow_empty_value = false, $source_lang = '' ) {
208
  PLL_WPML_Compat::instance()->register_string( $context, $name, $string );
209
  }
210
  }
211
 
212
- /**
213
- * Removes a string from the "strings translation" panel
214
- *
215
- * @since 1.0.2
216
- *
217
- * @param string $context the group in which the string is registered, defaults to 'polylang'
218
- * @param string $name a unique name for the string
219
- */
220
  if ( ! function_exists( 'icl_unregister_string' ) ) {
 
 
 
 
 
 
 
 
221
  function icl_unregister_string( $context, $name ) {
222
  PLL_WPML_Compat::instance()->unregister_string( $context, $name );
223
  }
224
  }
225
 
226
- /**
227
- * Gets the translated value of a string ( previously registered with icl_register_string or pll_register_string )
228
- *
229
- * @since 0.9.3
230
- * @since 1.9.2 argument 3 is optional
231
- * @since 2.0 add support for arguments 4 to 6
232
- *
233
- * @param string $context the group in which the string is registered
234
- * @param string $name a unique name for the string
235
- * @param string $string the string to translate, optional for strings registered with icl_register_string
236
- * @param bool|null $has_translation optional, not supported in Polylang
237
- * @param bool $bool optional, not used
238
- * @param string|null $lang optional, return the translation in this language, defaults to current language
239
- * @return string the translated string
240
- */
241
  if ( ! function_exists( 'icl_t' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  function icl_t( $context, $name, $string = false, &$has_translation = null, $bool = false, $lang = null ) {
243
  return icl_translate( $context, $name, $string, false, $has_translation, $lang );
244
  }
245
  }
246
 
247
- /**
248
- * Undocumented function used by NextGen Gallery
249
- * used in PLL_Plugins_Compat for Jetpack with only 3 arguments
250
- *
251
- * @since 1.0.2
252
- * @since 2.0 add support for arguments 5 and 6, strings are no more automatically registered
253
- *
254
- * @param string $context the group in which the string is registered
255
- * @param string $name a unique name for the string
256
- * @param string $string the string to translate, optional for strings registered with icl_register_string
257
- * @param bool $bool optional, not used
258
- * @param bool|null $has_translation optional, not supported in Polylang
259
- * @param string|null $lang optional, return the translation in this language, defaults to current language
260
- * @return string the translated string
261
- */
262
  if ( ! function_exists( 'icl_translate' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
  function icl_translate( $context, $name, $string = false, $bool = false, &$has_translation = null, $lang = null ) {
264
  // FIXME WPML can automatically registers the string based on an option
265
  if ( empty( $string ) ) {
@@ -269,17 +273,17 @@ if ( ! function_exists( 'icl_translate' ) ) {
269
  }
270
  }
271
 
272
- /**
273
- * Undocumented function used by Types
274
- * FIXME: tested only with Types
275
- * probably incomplete as Types locks the custom fields for a new post, but not when edited
276
- * This is probably linked to the fact that WPML has always an original post in the default language and not Polylang :)
277
- *
278
- * @since 1.1.2
279
- *
280
- * @return array
281
- */
282
  if ( ! function_exists( 'wpml_get_copied_fields_for_post_edit' ) ) {
 
 
 
 
 
 
 
 
 
 
283
  function wpml_get_copied_fields_for_post_edit() {
284
  if ( empty( $_GET['from_post'] ) ) {
285
  return array();
@@ -300,28 +304,28 @@ if ( ! function_exists( 'wpml_get_copied_fields_for_post_edit' ) ) {
300
  }
301
  }
302
 
303
- /**
304
- * Undocumented function used by Warp 6 by Yootheme
305
- *
306
- * @since 1.0.5
307
- *
308
- * @return string default language code
309
- */
310
  if ( ! function_exists( 'icl_get_default_language' ) ) {
 
 
 
 
 
 
 
311
  function icl_get_default_language() {
312
  return pll_default_language();
313
  }
314
  }
315
 
316
- /**
317
- * Undocumented function reported to be used by Table Rate Shipping for WooCommerce
318
- * @see https://wordpress.org/support/topic/add-wpml-compatibility-function
319
- *
320
- * @since 1.8.2
321
- *
322
- * @return string default language code
323
- */
324
  if ( ! function_exists( 'wpml_get_default_language' ) ) {
 
 
 
 
 
 
 
 
325
  function wpml_get_default_language() {
326
  return pll_default_language();
327
  }
6
  * But a lot of 3rd party plugins / themes are still using these functions
7
  */
8
 
 
 
 
 
 
 
 
9
  if ( ! function_exists( 'icl_get_home_url' ) ) {
10
+ /**
11
+ * Link to the home page in the active language
12
+ *
13
+ * @since 0.9.4
14
+ *
15
+ * @return string
16
+ */
17
  function icl_get_home_url() {
18
  return pll_home_url();
19
  }
20
  }
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  if ( ! function_exists( 'icl_get_languages' ) ) {
23
+ /**
24
+ * Used for building custom language selectors
25
+ * available only on frontend
26
+ *
27
+ * list of paramaters accepted in $args
28
+ *
29
+ * skip_missing => wether to skip missing translation or not, 0 or 1, defaults to 0
30
+ * orderby => 'id', 'code', 'name', defaults to 'id'
31
+ * order => 'ASC' or 'DESC', defaults to 'ASC'
32
+ * link_empty_to => link to use when the translation is missing {$lang} is replaced by the language code
33
+ *
34
+ * list of parameters returned per language:
35
+ *
36
+ * id => the language id
37
+ * active => wether this is the active language or no, 0 or 1
38
+ * native_name => the language name
39
+ * missing => wether the translation is missing or not, 0 or 1
40
+ * translated_name => empty, does not exist in Polylang
41
+ * language_code => the language code ( slug )
42
+ * country_flag_url => the url of the flag
43
+ * url => the url of the translation
44
+ *
45
+ * @since 1.0
46
+ *
47
+ * @param string|array $args optional
48
+ * @return array array of arrays per language
49
+ */
50
  function icl_get_languages( $args = '' ) {
51
  $args = wp_parse_args( $args, array( 'skip_missing' => 0, 'orderby' => 'id', 'order' => 'ASC' ) );
52
  $orderby = ( isset( $args['orderby'] ) && 'code' == $args['orderby'] ) ? 'slug' : ( isset( $args['orderby'] ) && 'name' == $args['orderby'] ? 'name' : 'id' );
78
  str_replace( '{$lang}', $lang->slug, $args['link_empty_to'] ) ),
79
  );
80
  }
81
+
82
+ // Apply undocumented WPML filter
83
+ $arr = apply_filters( 'icl_ls_languages', $arr );
84
+
85
  return $arr;
86
  }
87
  }
88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  if ( ! function_exists( 'icl_link_to_element' ) ) {
90
+ /**
91
+ * Used for creating language dependent links in themes
92
+ *
93
+ * @since 1.0
94
+ * @since 2.0 add support for arguments 6 and 7
95
+ *
96
+ * @param int $id object id
97
+ * @param string $type optional, post type or taxonomy name of the object, defaults to 'post'
98
+ * @param string $text optional, the link text. If not specified will produce the name of the element in the current language
99
+ * @param array $args optional, an array of arguments to add to the link, defaults to empty
100
+ * @param string $anchor optional, the anchor to add to the link, defaults to empty
101
+ * @param bool $echo optional, whether to echo the link, defaults to true
102
+ * @param bool $return_original_if_missing optional, whether to return a value if the translation is missing
103
+ * @return string a language dependent link
104
+ */
105
  function icl_link_to_element( $id, $type = 'post', $text = '', $args = array(), $anchor = '', $echo = true, $return_original_if_missing = true ) {
106
  if ( 'tag' == $type ) {
107
  $type = 'post_tag';
148
  }
149
  }
150
 
 
 
 
 
 
 
 
 
 
 
 
151
  if ( ! function_exists( 'icl_object_id' ) ) {
152
+ /**
153
+ * Used for calculating the IDs of objects (usually categories) in the current language
154
+ *
155
+ * @since 0.9.5
156
+ *
157
+ * @param int $id object id
158
+ * @param string $type optional, post type or taxonomy name of the object, defaults to 'post'
159
+ * @param bool $return_original_if_missing optional, true if Polylang should return the original id if the translation is missing, defaults to false
160
+ * @param string $lang optional, language code, defaults to current language
161
+ * @return int|null the object id of the translation, null if the translation is missing and $return_original_if_missing set to false
162
+ */
163
  function icl_object_id( $id, $type = 'post', $return_original_if_missing = false, $lang = false ) {
164
  $pll_type = ( 'post' === $type || pll_is_translated_post_type( $type ) ) ? 'post' : ( 'term' === $type || pll_is_translated_taxonomy( $type ) ? 'term' : false );
165
  return $pll_type && ( $lang = $lang ? $lang : pll_current_language() ) && ( $tr_id = PLL()->model->$pll_type->get_translation( $id, $lang ) ) ? $tr_id :
167
  }
168
  }
169
 
 
 
 
 
 
 
 
 
 
 
 
170
  if ( ! function_exists( 'wpml_get_language_information' ) ) {
171
+ /**
172
+ * Undocumented function used by the theme Maya
173
+ * returns the post language
174
+ * @see original WPML code at https://wpml.org/forums/topic/canonical-urls-for-wpml-duplicated-posts/#post-52198
175
+ *
176
+ * @since 1.8
177
+ *
178
+ * @param null $empty optional, not used
179
+ * @param int $post_id optional, post id, defaults to current post
180
+ * @return array
181
+ */
182
  function wpml_get_language_information( $empty = null, $post_id = null ) {
183
  if ( empty( $post_id ) ) {
184
  $post_id = get_the_ID();
191
  'text_direction' => (bool) $lang->is_rtl,
192
  'display_name' => $lang->name, // Seems to be the post language name displayed in the current language, not a feature in Polylang
193
  'native_name' => $lang->name,
194
+ 'different_language' => pll_current_language() !== $lang->slug,
195
  );
196
  }
197
  }
198
 
 
 
 
 
 
 
 
 
 
 
 
199
  if ( ! function_exists( 'icl_register_string' ) ) {
200
+ /**
201
+ * Registers a string for translation in the "strings translation" panel
202
+ *
203
+ * @since 0.9.3
204
+ *
205
+ * @param string $context the group in which the string is registered, defaults to 'polylang'
206
+ * @param string $name a unique name for the string
207
+ * @param string $string the string to register
208
+ * @param bool $allow_empty_value not used
209
+ * @param string $source_lang not used by Polylang
210
+ */
211
  function icl_register_string( $context, $name, $string, $allow_empty_value = false, $source_lang = '' ) {
212
  PLL_WPML_Compat::instance()->register_string( $context, $name, $string );
213
  }
214
  }
215
 
 
 
 
 
 
 
 
 
216
  if ( ! function_exists( 'icl_unregister_string' ) ) {
217
+ /**
218
+ * Removes a string from the "strings translation" panel
219
+ *
220
+ * @since 1.0.2
221
+ *
222
+ * @param string $context the group in which the string is registered, defaults to 'polylang'
223
+ * @param string $name a unique name for the string
224
+ */
225
  function icl_unregister_string( $context, $name ) {
226
  PLL_WPML_Compat::instance()->unregister_string( $context, $name );
227
  }
228
  }
229
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  if ( ! function_exists( 'icl_t' ) ) {
231
+ /**
232
+ * Gets the translated value of a string ( previously registered with icl_register_string or pll_register_string )
233
+ *
234
+ * @since 0.9.3
235
+ * @since 1.9.2 argument 3 is optional
236
+ * @since 2.0 add support for arguments 4 to 6
237
+ *
238
+ * @param string $context the group in which the string is registered
239
+ * @param string $name a unique name for the string
240
+ * @param string $string the string to translate, optional for strings registered with icl_register_string
241
+ * @param bool|null $has_translation optional, not supported in Polylang
242
+ * @param bool $bool optional, not used
243
+ * @param string|null $lang optional, return the translation in this language, defaults to current language
244
+ * @return string the translated string
245
+ */
246
  function icl_t( $context, $name, $string = false, &$has_translation = null, $bool = false, $lang = null ) {
247
  return icl_translate( $context, $name, $string, false, $has_translation, $lang );
248
  }
249
  }
250
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  if ( ! function_exists( 'icl_translate' ) ) {
252
+ /**
253
+ * Undocumented function used by NextGen Gallery
254
+ * used in PLL_Plugins_Compat for Jetpack with only 3 arguments
255
+ *
256
+ * @since 1.0.2
257
+ * @since 2.0 add support for arguments 5 and 6, strings are no more automatically registered
258
+ *
259
+ * @param string $context the group in which the string is registered
260
+ * @param string $name a unique name for the string
261
+ * @param string $string the string to translate, optional for strings registered with icl_register_string
262
+ * @param bool $bool optional, not used
263
+ * @param bool|null $has_translation optional, not supported in Polylang
264
+ * @param string|null $lang optional, return the translation in this language, defaults to current language
265
+ * @return string the translated string
266
+ */
267
  function icl_translate( $context, $name, $string = false, $bool = false, &$has_translation = null, $lang = null ) {
268
  // FIXME WPML can automatically registers the string based on an option
269
  if ( empty( $string ) ) {
273
  }
274
  }
275
 
 
 
 
 
 
 
 
 
 
 
276
  if ( ! function_exists( 'wpml_get_copied_fields_for_post_edit' ) ) {
277
+ /**
278
+ * Undocumented function used by Types
279
+ * FIXME: tested only with Types
280
+ * probably incomplete as Types locks the custom fields for a new post, but not when edited
281
+ * This is probably linked to the fact that WPML has always an original post in the default language and not Polylang :)
282
+ *
283
+ * @since 1.1.2
284
+ *
285
+ * @return array
286
+ */
287
  function wpml_get_copied_fields_for_post_edit() {
288
  if ( empty( $_GET['from_post'] ) ) {
289
  return array();
304
  }
305
  }
306
 
 
 
 
 
 
 
 
307
  if ( ! function_exists( 'icl_get_default_language' ) ) {
308
+ /**
309
+ * Undocumented function used by Warp 6 by Yootheme
310
+ *
311
+ * @since 1.0.5
312
+ *
313
+ * @return string default language code
314
+ */
315
  function icl_get_default_language() {
316
  return pll_default_language();
317
  }
318
  }
319
 
 
 
 
 
 
 
 
 
320
  if ( ! function_exists( 'wpml_get_default_language' ) ) {
321
+ /**
322
+ * Undocumented function reported to be used by Table Rate Shipping for WooCommerce
323
+ * @see https://wordpress.org/support/topic/add-wpml-compatibility-function
324
+ *
325
+ * @since 1.8.2
326
+ *
327
+ * @return string default language code
328
+ */
329
  function wpml_get_default_language() {
330
  return pll_default_language();
331
  }
polylang.php CHANGED
@@ -1,15 +1,15 @@
1
  <?php
2
 
3
- /*
4
  Plugin Name: Polylang
5
  Plugin URI: https://polylang.pro
6
- Version: 2.1.6
7
  Author: Frédéric Demarle
8
  Author uri: https://polylang.pro
9
  Description: Adds multilingual capability to WordPress
10
  Text Domain: polylang
11
  Domain Path: /languages
12
- */
13
 
14
  /*
15
  * Copyright 2011-2017 Frédéric Demarle
@@ -35,7 +35,7 @@ if ( ! defined( 'ABSPATH' ) ) {
35
  exit; // don't access directly
36
  };
37
 
38
- define( 'POLYLANG_VERSION', '2.1.6' );
39
  define( 'PLL_MIN_WP_VERSION', '4.4' );
40
 
41
  define( 'POLYLANG_FILE', __FILE__ ); // this file
1
  <?php
2
 
3
+ /**
4
  Plugin Name: Polylang
5
  Plugin URI: https://polylang.pro
6
+ Version: 2.2
7
  Author: Frédéric Demarle
8
  Author uri: https://polylang.pro
9
  Description: Adds multilingual capability to WordPress
10
  Text Domain: polylang
11
  Domain Path: /languages
12
+ */
13
 
14
  /*
15
  * Copyright 2011-2017 Frédéric Demarle
35
  exit; // don't access directly
36
  };
37
 
38
+ define( 'POLYLANG_VERSION', '2.2' );
39
  define( 'PLL_MIN_WP_VERSION', '4.4' );
40
 
41
  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.8
7
- Stable tag: 2.1.6
8
  License: GPLv2 or later
9
 
10
  Making WordPress multilingual
@@ -76,6 +76,43 @@ Don't hesitate to [give your feedback](http://wordpress.org/support/view/plugin-
76
 
77
  == Changelog ==
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  = 2.1.6 (2017-07-17) =
80
 
81
  * Pro: fix duplicate post button not working in PHP 7.1
4
  Tags: multilingual, bilingual, translate, translation, language, multilanguage, international, localization
5
  Requires at least: 4.4
6
  Tested up to: 4.8
7
+ Stable tag: 2.2
8
  License: GPLv2 or later
9
 
10
  Making WordPress multilingual
76
 
77
  == Changelog ==
78
 
79
+ = 2.2 (2017-08-16) =
80
+
81
+ * Pro: Add support for the REST API
82
+ * Pro: Add integration with The Events Calendar
83
+ * Pro: Refactor ACF Pro integration for post metas and integrate term metas
84
+ * Pro: Ask confirmation if synchronizing a post overwrites an existing translation
85
+ * Pro: Separate sync post logic from interface
86
+ * Pro: Fix 'Detect browser language' option automatically deactivated
87
+ * Pro: Fix redirect to 404 when the 'page' slug translation includes non alphanumeric characters.
88
+ * Pro: Fix untranslated post type archive slug
89
+ * Pro: Fix ACF taxonomy fields not copied when the taxonomy is not translated #156
90
+ * Pro: Fix fatal error with ACF4
91
+ * Support a different content text direction in admin #45
92
+ * Add support for wildcards and 'copy-once' attribute in wpml-config.xml
93
+ * Add minimal support for the filters 'wpml_display_language_names' and 'icl_ls_languages'
94
+ * Improve compatibility with the plugin WordPress MU Domain Mapping #116
95
+ * Improve speed of the sticky posts filter #41
96
+ * Remove redirect_lang option for multiple domains and subdomains
97
+ * Use secure cookie when using SSL
98
+ * Allow to copy/sync term metas with the filter 'pll_copy_term_metas'
99
+ * Filter ajax requests in term.php according to the term language
100
+ * Add error message in customizer when setting an untranslated static front page #47
101
+ * Load static page class only if we are using a static front page
102
+ * Refactor parse_query filters to use the same code on frontend and admin
103
+ * Don't use add_language_to_link in filters
104
+ * Move ajaxPrefilter footer script on top
105
+ * Use wp_doing_ajax() instead of DOING_AJAX constant
106
+ * Fix queries custom tax not excluded from language filter on admin
107
+ * Fix WP translation not loaded when the language is set from the content on multisite.
108
+ * Fix the list of core post types in PLL_OLT_Manager for WP 4.7+
109
+ * Fix post name and tag slug incorrectly sanitized for German and Danish
110
+ * Fix lang attribute in dropdowns
111
+ * Fix wpml_permalink filter #139
112
+ * Fix WPML constants undefined on backend #151
113
+ * Fix a conflict with the plugin Custom Permalinks #143
114
+ * Fix menu location unexpectedly unset
115
+
116
  = 2.1.6 (2017-07-17) =
117
 
118
  * Pro: fix duplicate post button not working in PHP 7.1
settings/settings-browser.php CHANGED
@@ -76,7 +76,7 @@ class PLL_Settings_Browser extends PLL_Settings_Module {
76
  $( "input[name='force_lang']" ).change( function() {
77
  var value = $( this ).val();
78
  if ( 3 > value ) {
79
- $( "#pll-module-browser" ).<?php echo $func;?>.children( "td" ).children( ".row-actions" ).html( '<?php echo $link; ?>' );
80
  }
81
  else {
82
  $( "#pll-module-browser" ).removeClass( "active" ).addClass( "inactive" ).children( "td" ).children( ".row-actions" ).html( '<?php echo $deactivated; ?>' );
@@ -84,6 +84,7 @@ class PLL_Settings_Browser extends PLL_Settings_Module {
84
  } );
85
  } )( jQuery );
86
  // ]]>
87
- </script><?php
 
88
  }
89
  }
76
  $( "input[name='force_lang']" ).change( function() {
77
  var value = $( this ).val();
78
  if ( 3 > value ) {
79
+ $( "#pll-module-browser" ).<?php echo $func; ?>.children( "td" ).children( ".row-actions" ).html( '<?php echo $link; ?>' );
80
  }
81
  else {
82
  $( "#pll-module-browser" ).removeClass( "active" ).addClass( "inactive" ).children( "td" ).children( ".row-actions" ).html( '<?php echo $deactivated; ?>' );
84
  } );
85
  } )( jQuery );
86
  // ]]>
87
+ </script>
88
+ <?php
89
  }
90
  }
settings/settings-cpt.php CHANGED
@@ -8,7 +8,7 @@
8
  class PLL_Settings_CPT extends PLL_Settings_Module {
9
 
10
  /**
11
- * constructor
12
  *
13
  * @since 1.8
14
  *
@@ -34,7 +34,7 @@ class PLL_Settings_CPT extends PLL_Settings_Module {
34
  }
35
 
36
  /**
37
- * tells if the module is active
38
  *
39
  * @since 1.8
40
  *
@@ -45,50 +45,57 @@ class PLL_Settings_CPT extends PLL_Settings_Module {
45
  }
46
 
47
  /**
48
- * displays the settings form
49
  *
50
  * @since 1.8
51
  */
52
  protected function form() {
53
  if ( ! empty( $this->post_types ) ) {?>
54
- <h4><?php esc_html_e( 'Custom post types', 'polylang' ) ?></h4>
55
- <ul class="pll-inline-block-list"><?php
 
56
  foreach ( $this->post_types as $post_type ) {
57
  $pt = get_post_type_object( $post_type );
58
  if ( ! empty( $pt ) ) {
59
  printf(
60
  '<li><label><input name="post_types[%s]" type="checkbox" value="1" %s /> %s</label></li>',
61
  esc_attr( $post_type ),
62
- in_array( $post_type, $this->options['post_types'] ) ? 'checked="checked"' :'',
63
  esc_html( $pt->labels->name )
64
  );
65
  }
66
- }?>
 
67
  </ul>
68
- <p class="description"><?php esc_html_e( 'Activate languages and translations for custom post types.', 'polylang' );?></p><?php
 
69
  }
70
 
71
- if ( ! empty( $this->taxonomies ) ) {?>
72
- <h4><?php esc_html_e( 'Custom taxonomies', 'polylang' ) ?></h4>
73
- <ul class="pll-inline-block-list"><?php
 
 
74
  foreach ( $this->taxonomies as $taxonomy ) {
75
  $tax = get_taxonomy( $taxonomy );
76
  if ( ! empty( $tax ) ) {
77
  printf(
78
  '<li><label><input name="taxonomies[%s]" type="checkbox" value="1" %s /> %s</label></li>',
79
  esc_attr( $taxonomy ),
80
- in_array( $taxonomy, $this->options['taxonomies'] ) ? 'checked="checked"' :'',
81
  esc_html( $tax->labels->name )
82
  );
83
  }
84
- }?>
 
85
  </ul>
86
- <p class="description"><?php esc_html_e( 'Activate languages and translations for custom taxonomies.', 'polylang' );?></p><?php
 
87
  }
88
  }
89
 
90
  /**
91
- * sanitizes the settings before saving
92
  *
93
  * @since 1.8
94
  *
@@ -98,6 +105,6 @@ class PLL_Settings_CPT extends PLL_Settings_Module {
98
  foreach ( array( 'post_types', 'taxonomies' ) as $key ) {
99
  $newoptions[ $key ] = empty( $options[ $key ] ) ? array() : array_keys( $options[ $key ], 1 );
100
  }
101
- return $newoptions; // take care to return only validated options
102
  }
103
  }
8
  class PLL_Settings_CPT extends PLL_Settings_Module {
9
 
10
  /**
11
+ * Constructor
12
  *
13
  * @since 1.8
14
  *
34
  }
35
 
36
  /**
37
+ * Tells if the module is active
38
  *
39
  * @since 1.8
40
  *
45
  }
46
 
47
  /**
48
+ * Displays the settings form
49
  *
50
  * @since 1.8
51
  */
52
  protected function form() {
53
  if ( ! empty( $this->post_types ) ) {?>
54
+ <h4><?php esc_html_e( 'Custom post types', 'polylang' ); ?></h4>
55
+ <ul class="pll-inline-block-list">
56
+ <?php
57
  foreach ( $this->post_types as $post_type ) {
58
  $pt = get_post_type_object( $post_type );
59
  if ( ! empty( $pt ) ) {
60
  printf(
61
  '<li><label><input name="post_types[%s]" type="checkbox" value="1" %s /> %s</label></li>',
62
  esc_attr( $post_type ),
63
+ in_array( $post_type, $this->options['post_types'] ) ? 'checked="checked"' : '',
64
  esc_html( $pt->labels->name )
65
  );
66
  }
67
+ }
68
+ ?>
69
  </ul>
70
+ <p class="description"><?php esc_html_e( 'Activate languages and translations for custom post types.', 'polylang' ); ?></p>
71
+ <?php
72
  }
73
 
74
+ if ( ! empty( $this->taxonomies ) ) {
75
+ ?>
76
+ <h4><?php esc_html_e( 'Custom taxonomies', 'polylang' ); ?></h4>
77
+ <ul class="pll-inline-block-list">
78
+ <?php
79
  foreach ( $this->taxonomies as $taxonomy ) {
80
  $tax = get_taxonomy( $taxonomy );
81
  if ( ! empty( $tax ) ) {
82
  printf(
83
  '<li><label><input name="taxonomies[%s]" type="checkbox" value="1" %s /> %s</label></li>',
84
  esc_attr( $taxonomy ),
85
+ in_array( $taxonomy, $this->options['taxonomies'] ) ? 'checked="checked"' : '',
86
  esc_html( $tax->labels->name )
87
  );
88
  }
89
+ }
90
+ ?>
91
  </ul>
92
+ <p class="description"><?php esc_html_e( 'Activate languages and translations for custom taxonomies.', 'polylang' ); ?></p>
93
+ <?php
94
  }
95
  }
96
 
97
  /**
98
+ * Sanitizes the settings before saving
99
  *
100
  * @since 1.8
101
  *
105
  foreach ( array( 'post_types', 'taxonomies' ) as $key ) {
106
  $newoptions[ $key ] = empty( $options[ $key ] ) ? array() : array_keys( $options[ $key ], 1 );
107
  }
108
+ return $newoptions; // Take care to return only validated options
109
  }
110
  }
settings/settings-licenses.php CHANGED
@@ -47,11 +47,14 @@ class PLL_Settings_Licenses extends PLL_Settings_Module {
47
  */
48
  protected function form() {
49
  if ( ! empty( $this->items ) ) { ?>
50
- <table id="pll-licenses-table" class="form-table"><?php
51
- foreach ( $this->items as $item ) {
52
- echo $this->get_row( $item );
53
- } ?>
54
- </table><?php
 
 
 
55
  }
56
  }
57
 
@@ -90,7 +93,7 @@ class PLL_Settings_Licenses extends PLL_Settings_Module {
90
  $class = 'notice-error notice-alt';
91
 
92
  switch ( $license->error ) {
93
- case 'expired' :
94
  $message = sprintf(
95
  /* translators: %1$s is a date, %2$s and %3$s are html tags */
96
  __( 'Your license key expired on %1$s. Please %2$srenew your license key%3$s.', 'polylang' ),
@@ -98,19 +101,19 @@ class PLL_Settings_Licenses extends PLL_Settings_Module {
98
  sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/checkout/?edd_license_key=' . $item->license_key ),
99
  '</a>'
100
  );
101
- break;
102
 
103
- case 'missing' :
104
  $message = sprintf(
105
  /* translators: %s are html tags */
106
  __( 'Invalid license. Please %svisit your account page%s and verify it.', 'polylang' ),
107
  sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account' ),
108
  '</a>'
109
  );
110
- break;
111
 
112
- case 'invalid' :
113
- case 'site_inactive' :
114
  $message = sprintf(
115
  /* translators: %1$s is a product name, %2$s and %3$s are html tags */
116
  __( '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' ),
@@ -118,21 +121,21 @@ class PLL_Settings_Licenses extends PLL_Settings_Module {
118
  sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account' ),
119
  '</a>'
120
  );
121
- break;
122
 
123
- case 'item_name_mismatch' :
124
  /* translators: %s is a product name */
125
  $message = sprintf( __( 'This is not a %s license key.', 'polylang' ), $item->name );
126
  break;
127
 
128
  case 'no_activations_left':
129
- /* translators: %s are html tags */
130
  $message = sprintf(
 
131
  __( 'Your license key has reached its activation limit. %sView possible upgrades%s now.', 'polylang' ),
132
  sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account' ),
133
  '</a>'
134
  );
135
- break;
136
  }
137
  } else {
138
  $class = 'license-valid';
47
  */
48
  protected function form() {
49
  if ( ! empty( $this->items ) ) { ?>
50
+ <table id="pll-licenses-table" class="form-table">
51
+ <?php
52
+ foreach ( $this->items as $item ) {
53
+ echo $this->get_row( $item );
54
+ }
55
+ ?>
56
+ </table>
57
+ <?php
58
  }
59
  }
60
 
93
  $class = 'notice-error notice-alt';
94
 
95
  switch ( $license->error ) {
96
+ case 'expired':
97
  $message = sprintf(
98
  /* translators: %1$s is a date, %2$s and %3$s are html tags */
99
  __( 'Your license key expired on %1$s. Please %2$srenew your license key%3$s.', 'polylang' ),
101
  sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/checkout/?edd_license_key=' . $item->license_key ),
102
  '</a>'
103
  );
104
+ break;
105
 
106
+ case 'missing':
107
  $message = sprintf(
108
  /* translators: %s are html tags */
109
  __( 'Invalid license. Please %svisit your account page%s and verify it.', 'polylang' ),
110
  sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account' ),
111
  '</a>'
112
  );
113
+ break;
114
 
115
+ case 'invalid':
116
+ case 'site_inactive':
117
  $message = sprintf(
118
  /* translators: %1$s is a product name, %2$s and %3$s are html tags */
119
  __( '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' ),
121
  sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account' ),
122
  '</a>'
123
  );
124
+ break;
125
 
126
+ case 'item_name_mismatch':
127
  /* translators: %s is a product name */
128
  $message = sprintf( __( 'This is not a %s license key.', 'polylang' ), $item->name );
129
  break;
130
 
131
  case 'no_activations_left':
 
132
  $message = sprintf(
133
+ /* translators: %s are html tags */
134
  __( 'Your license key has reached its activation limit. %sView possible upgrades%s now.', 'polylang' ),
135
  sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account' ),
136
  '</a>'
137
  );
138
+ break;
139
  }
140
  } else {
141
  $class = 'license-valid';
settings/settings-module.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /**
4
- * base class for all settings
5
  *
6
  * @since 1.8
7
  */
@@ -12,12 +12,12 @@ class PLL_Settings_Module {
12
  protected $action_links, $buttons;
13
 
14
  /**
15
- * constructor
16
  *
17
  * @since 1.8
18
  *
19
- * @param object $polylang polylang object
20
- * @param array $args
21
  */
22
  public function __construct( &$polylang, $args ) {
23
  $this->options = &$polylang->options;
@@ -34,7 +34,7 @@ class PLL_Settings_Module {
34
  $this->$prop = $value;
35
  }
36
 
37
- // all possible action links, even if not always a link ;- )
38
  $this->action_links = array(
39
  'configure' => sprintf(
40
  '<a title="%s" href="%s">%s</a>',
@@ -67,12 +67,12 @@ class PLL_Settings_Module {
67
  'save' => sprintf( '<button type="button" class="button button-primary save">%s</button>', esc_html__( 'Save Changes' ) ),
68
  );
69
 
70
- // ajax action to save options
71
  add_action( 'wp_ajax_pll_save_options', array( $this, 'save_options' ) );
72
  }
73
 
74
  /**
75
- * tells if the module is active
76
  *
77
  * @since 1.8
78
  *
@@ -83,7 +83,7 @@ class PLL_Settings_Module {
83
  }
84
 
85
  /**
86
- * activates the module
87
  *
88
  * @since 1.8
89
  */
@@ -95,7 +95,7 @@ class PLL_Settings_Module {
95
  }
96
 
97
  /**
98
- * deactivates the module
99
  *
100
  * @since 1.8
101
  */
@@ -107,17 +107,16 @@ class PLL_Settings_Module {
107
  }
108
 
109
  /**
110
- * protected method to display a configuration form
111
  *
112
  * @since 1.8
113
- *
114
  */
115
  protected function form() {
116
- // child classes can provide a form
117
  }
118
 
119
  /**
120
- * public method returning the form if any
121
  *
122
  * @since 1.8
123
  *
@@ -126,7 +125,7 @@ class PLL_Settings_Module {
126
  public function get_form() {
127
  static $form = false;
128
 
129
- // read the form only once
130
  if ( false === $form ) {
131
  ob_start();
132
  $this->form();
@@ -137,19 +136,19 @@ class PLL_Settings_Module {
137
  }
138
 
139
  /**
140
- * allows child classes to validate their options before saving
141
  *
142
  * @since 1.8
143
  *
144
- * @param array $options raw options
145
- * @param array options
146
  */
147
  protected function update( $options ) {
148
- return array(); // it's responsibility of the child class to decide what is saved
149
  }
150
 
151
  /**
152
- * ajax method to save the options
153
  *
154
  * @since 1.8
155
  */
@@ -160,29 +159,29 @@ class PLL_Settings_Module {
160
  }
161
 
162
  if ( $this->module == $_POST['module'] ) {
163
- // it's up to the child class to decide which options are saved, whether there are errors or not
164
  $post = array_diff_key( $_POST, array_flip( array( 'action', 'module', 'pll_ajax_backend', '_pll_nonce' ) ) );
165
  $options = $this->update( $post );
166
  $this->options = array_merge( $this->options, $options );
167
  update_option( 'polylang', $this->options );
168
 
169
- // refresh language cache in case home urls have been modified
170
  $this->model->clean_languages_cache();
171
 
172
- // refresh rewrite rules in case rewrite, hide_default, post types or taxonomies options have been modified
173
- // don't use flush_rewrite_rules as we don't have the right links model and permastruct
174
  delete_option( 'rewrite_rules' );
175
 
176
  ob_start();
177
 
178
  if ( ! get_settings_errors() ) {
179
- // send update message
180
  add_settings_error( 'general', 'settings_updated', __( 'Settings saved.' ), 'updated' );
181
  settings_errors();
182
  $x = new WP_Ajax_Response( array( 'what' => 'success', 'data' => ob_get_clean() ) );
183
  $x->send();
184
  } else {
185
- // send error messages
186
  settings_errors();
187
  $x = new WP_Ajax_Response( array( 'what' => 'error', 'data' => ob_get_clean() ) );
188
  $x->send();
@@ -191,7 +190,7 @@ class PLL_Settings_Module {
191
  }
192
 
193
  /**
194
- * get the row actions
195
  *
196
  * @since 1.8
197
  *
@@ -214,7 +213,7 @@ class PLL_Settings_Module {
214
  }
215
 
216
  /**
217
- * get the actions links
218
  *
219
  * @since 1.8
220
  *
@@ -225,7 +224,7 @@ class PLL_Settings_Module {
225
  }
226
 
227
  /**
228
- * default upgrade message ( to pro version )
229
  *
230
  * @since 1.9
231
  *
@@ -241,7 +240,7 @@ class PLL_Settings_Module {
241
  }
242
 
243
  /**
244
- * allows child classes to display an upgrade message
245
  *
246
  * @since 1.9
247
  *
@@ -252,7 +251,7 @@ class PLL_Settings_Module {
252
  }
253
 
254
  /**
255
- * get the buttons
256
  *
257
  * @since 1.9
258
  *
1
  <?php
2
 
3
  /**
4
+ * Base class for all settings
5
  *
6
  * @since 1.8
7
  */
12
  protected $action_links, $buttons;
13
 
14
  /**
15
+ * Constructor
16
  *
17
  * @since 1.8
18
  *
19
+ * @param object $polylang Polylang object
20
+ * @param array $args
21
  */
22
  public function __construct( &$polylang, $args ) {
23
  $this->options = &$polylang->options;
34
  $this->$prop = $value;
35
  }
36
 
37
+ // All possible action links, even if not always a link ;-)
38
  $this->action_links = array(
39
  'configure' => sprintf(
40
  '<a title="%s" href="%s">%s</a>',
67
  'save' => sprintf( '<button type="button" class="button button-primary save">%s</button>', esc_html__( 'Save Changes' ) ),
68
  );
69
 
70
+ // Ajax action to save options
71
  add_action( 'wp_ajax_pll_save_options', array( $this, 'save_options' ) );
72
  }
73
 
74
  /**
75
+ * Tells if the module is active
76
  *
77
  * @since 1.8
78
  *
83
  }
84
 
85
  /**
86
+ * Activates the module
87
  *
88
  * @since 1.8
89
  */
95
  }
96
 
97
  /**
98
+ * Deactivates the module
99
  *
100
  * @since 1.8
101
  */
107
  }
108
 
109
  /**
110
+ * Protected method to display a configuration form
111
  *
112
  * @since 1.8
 
113
  */
114
  protected function form() {
115
+ // Child classes can provide a form
116
  }
117
 
118
  /**
119
+ * Public method returning the form if any
120
  *
121
  * @since 1.8
122
  *
125
  public function get_form() {
126
  static $form = false;
127
 
128
+ // Read the form only once
129
  if ( false === $form ) {
130
  ob_start();
131
  $this->form();
136
  }
137
 
138
  /**
139
+ * Allows child classes to validate their options before saving
140
  *
141
  * @since 1.8
142
  *
143
+ * @param array $options Raw options
144
+ * @return array Options
145
  */
146
  protected function update( $options ) {
147
+ return array(); // It's responsibility of the child class to decide what is saved
148
  }
149
 
150
  /**
151
+ * Ajax method to save the options
152
  *
153
  * @since 1.8
154
  */
159
  }
160
 
161
  if ( $this->module == $_POST['module'] ) {
162
+ // It's up to the child class to decide which options are saved, whether there are errors or not
163
  $post = array_diff_key( $_POST, array_flip( array( 'action', 'module', 'pll_ajax_backend', '_pll_nonce' ) ) );
164
  $options = $this->update( $post );
165
  $this->options = array_merge( $this->options, $options );
166
  update_option( 'polylang', $this->options );
167
 
168
+ // Refresh language cache in case home urls have been modified
169
  $this->model->clean_languages_cache();
170
 
171
+ // Refresh rewrite rules in case rewrite, hide_default, post types or taxonomies options have been modified
172
+ // Don't use flush_rewrite_rules as we don't have the right links model and permastruct
173
  delete_option( 'rewrite_rules' );
174
 
175
  ob_start();
176
 
177
  if ( ! get_settings_errors() ) {
178
+ // Send update message
179
  add_settings_error( 'general', 'settings_updated', __( 'Settings saved.' ), 'updated' );
180
  settings_errors();
181
  $x = new WP_Ajax_Response( array( 'what' => 'success', 'data' => ob_get_clean() ) );
182
  $x->send();
183
  } else {
184
+ // Send error messages
185
  settings_errors();
186
  $x = new WP_Ajax_Response( array( 'what' => 'error', 'data' => ob_get_clean() ) );
187
  $x->send();
190
  }
191
 
192
  /**
193
+ * Get the row actions
194
  *
195
  * @since 1.8
196
  *
213
  }
214
 
215
  /**
216
+ * Get the actions links
217
  *
218
  * @since 1.8
219
  *
224
  }
225
 
226
  /**
227
+ * Default upgrade message ( to Pro version )
228
  *
229
  * @since 1.9
230
  *
240
  }
241
 
242
  /**
243
+ * Allows child classes to display an upgrade message
244
  *
245
  * @since 1.9
246
  *
251
  }
252
 
253
  /**
254
+ * Get the buttons
255
  *
256
  * @since 1.9
257
  *
settings/settings-url.php CHANGED
@@ -32,40 +32,49 @@ class PLL_Settings_Url extends PLL_Settings_Module {
32
  * @since 1.8
33
  */
34
  protected function force_lang() {?>
35
- <label><?php
 
36
  printf(
37
  '<input name="force_lang" type="radio" value="0" %s /> %s',
38
  $this->options['force_lang'] ? '' : 'checked="checked"',
39
  esc_html__( 'The language is set from content', 'polylang' )
40
- );?>
 
41
  </label>
42
- <p class="description"><?php esc_html_e( 'Posts, pages, categories and tags urls are not modified.', 'polylang' );?></p>
43
- <label><?php
 
44
  printf(
45
  '<input name="force_lang" type="radio" value="1" %s/> %s',
46
  1 == $this->options['force_lang'] ? 'checked="checked"' : '',
47
  $this->links_model->using_permalinks ? esc_html__( 'The language is set from the directory name in pretty permalinks', 'polylang' ) : esc_html__( 'The language is set from the code in the URL', 'polylang' )
48
- );?>
 
49
  </label>
50
- <p class="description"><?php echo esc_html__( 'Example:', 'polylang' ) . ' <code>' . esc_html( home_url( $this->links_model->using_permalinks ? 'en/my-post/' : '?lang=en&p=1' ) ) . '</code>';?></p>
51
- <label><?php
 
52
  printf(
53
  '<input name="force_lang" type="radio" value="2" %s %s/> %s',
54
  $this->links_model->using_permalinks ? '' : 'disabled="disabled"',
55
  2 == $this->options['force_lang'] ? 'checked="checked"' : '',
56
  esc_html__( 'The language is set from the subdomain name in pretty permalinks', 'polylang' )
57
- );?>
 
58
  </label>
59
- <p class="description"><?php echo esc_html__( 'Example:', 'polylang' ) . ' <code>' . esc_html( str_replace( array( '://', 'www.' ), array( '://en.', '' ), home_url( 'my-post/' ) ) ) . '</code>';?></p>
60
- <label><?php
 
61
  printf(
62
  '<input name="force_lang" type="radio" value="3" %s %s/> %s',
63
  $this->links_model->using_permalinks ? '' : 'disabled="disabled"',
64
  3 == $this->options['force_lang'] ? 'checked="checked"' : '',
65
  esc_html__( 'The language is set from different domains', 'polylang' )
66
- );?>
 
67
  </label>
68
- <table id="pll-domains-table" class="form-table" <?php echo 3 == $this->options['force_lang'] ? '' : 'style="display: none;"'; ?>><?php
 
69
  foreach ( $this->model->get_languages_list() as $lg ) {
70
  printf(
71
  '<tr><td><label for="pll-domain[%1$s]">%2$s</label></td>' .
@@ -74,8 +83,10 @@ class PLL_Settings_Url extends PLL_Settings_Module {
74
  esc_attr( $lg->name ),
75
  esc_url( isset( $this->options['domains'][ $lg->slug ] ) ? $this->options['domains'][ $lg->slug ] : ( $lg->slug == $this->options['default_lang'] ? $this->links_model->home : '' ) )
76
  );
77
- }?>
78
- </table><?php
 
 
79
  }
80
 
81
  /**
@@ -83,14 +94,18 @@ class PLL_Settings_Url extends PLL_Settings_Module {
83
  *
84
  * @since 1.8
85
  */
86
- protected function hide_default() { ?>
87
- <label><?php
 
 
88
  printf(
89
  '<input name="hide_default" type="checkbox" value="1" %s /> %s',
90
- $this->options['hide_default'] ? 'checked="checked"' :'',
91
  esc_html__( 'Hide URL language information for default language', 'polylang' )
92
- );?>
93
- </label><?php
 
 
94
  }
95
 
96
  /**
@@ -98,25 +113,31 @@ class PLL_Settings_Url extends PLL_Settings_Module {
98
  *
99
  * @since 1.8
100
  */
101
- protected function rewrite() {?>
102
- <label><?php
 
 
103
  printf(
104
  '<input name="rewrite" type="radio" value="1" %s %s/> %s',
105
  $this->links_model->using_permalinks ? '' : 'disabled="disabled"',
106
  $this->options['rewrite'] ? 'checked="checked"' : '',
107
  esc_html__( 'Remove /language/ in pretty permalinks', 'polylang' )
108
- );?>
 
109
  </label>
110
- <p class="description"><?php echo esc_html__( 'Example:', 'polylang' ) . ' <code>' . esc_html( home_url( 'en/' ) ) . '</code>';?></p>
111
- <label><?php
 
112
  printf(
113
  '<input name="rewrite" type="radio" value="0" %s %s/> %s',
114
  $this->links_model->using_permalinks ? '' : 'disabled="disabled"',
115
  $this->options['rewrite'] ? '' : 'checked="checked"',
116
  esc_html__( 'Keep /language/ in pretty permalinks', 'polylang' )
117
- );?>
 
118
  </label>
119
- <p class="description"><?php echo esc_html__( 'Example:', 'polylang' ) . ' <code>' . esc_html( home_url( 'language/en/' ) ) . '</code>';?></p><?php
 
120
  }
121
 
122
  /**
@@ -124,15 +145,19 @@ class PLL_Settings_Url extends PLL_Settings_Module {
124
  *
125
  * @since 1.8
126
  */
127
- protected function redirect_lang() { ?>
128
- <label><?php
 
 
129
  printf(
130
  '<input name="redirect_lang" type="checkbox" value="1" %s/> %s',
131
- $this->options['redirect_lang'] ? 'checked="checked"' :'',
132
  esc_html__( 'The front page url contains the language code instead of the page name or page id', 'polylang' )
133
- );?>
 
134
  </label>
135
- <p class="description"><?php
 
136
  // That's nice to display the right home urls but don't forget that the page on front may have no language yet
137
  $lang = $this->model->post->get_language( $this->page_on_front );
138
  $lang = $lang ? $lang : $this->model->get_language( $this->options['default_lang'] );
@@ -141,8 +166,10 @@ class PLL_Settings_Url extends PLL_Settings_Module {
141
  esc_html__( 'Example: %s instead of %s', 'polylang' ),
142
  '<code>' . esc_html( $this->links_model->home_url( $lang ) ) . '</code>',
143
  '<code>' . esc_html( _get_page_link( $this->page_on_front ) ) . '</code>'
144
- ); ?>
145
- </p><?php
 
 
146
  }
147
 
148
  /**
@@ -150,30 +177,37 @@ class PLL_Settings_Url extends PLL_Settings_Module {
150
  *
151
  * @since 1.8
152
  */
153
- public function form() { ?>
 
154
  <div class="pll-settings-url-col">
155
- <fieldset class="pll-col-left pll-url" id="pll-force-lang"><?php
156
- $this->force_lang(); ?>
157
  </fieldset>
158
  </div>
159
 
160
  <div class="pll-settings-url-col">
161
- <fieldset class="pll-col-right pll-url" id="pll-hide-default" <?php echo 3 > $this->options['force_lang'] ? '' : 'style="display: none;"'; ?>><?php
162
- $this->hide_default(); ?>
163
- </fieldset><?php
164
-
165
- if ( $this->links_model->using_permalinks ) { ?>
166
- <fieldset class="pll-col-right pll-url" id="pll-rewrite" <?php echo 2 > $this->options['force_lang'] ? '' : 'style="display: none;"'; ?>><?php
167
- $this->rewrite(); ?>
168
- </fieldset><?php
 
 
169
  }
170
 
171
- if ( $this->page_on_front ) { ?>
172
- <fieldset class="pll-col-right pll-url" id="pll-redirect-lang"><?php
173
- $this->redirect_lang(); ?>
174
- </fieldset><?php
175
- } ?>
176
- </div><?php
 
 
 
 
177
  }
178
 
179
  /**
@@ -208,7 +242,10 @@ class PLL_Settings_Url extends PLL_Settings_Module {
208
  }
209
 
210
  if ( 3 == $options['force_lang'] ) {
211
- $newoptions['browser'] = $newoptions['hide_default'] = 0;
 
 
 
212
  }
213
 
214
  // Check if domains exist
32
  * @since 1.8
33
  */
34
  protected function force_lang() {?>
35
+ <label>
36
+ <?php
37
  printf(
38
  '<input name="force_lang" type="radio" value="0" %s /> %s',
39
  $this->options['force_lang'] ? '' : 'checked="checked"',
40
  esc_html__( 'The language is set from content', 'polylang' )
41
+ );
42
+ ?>
43
  </label>
44
+ <p class="description"><?php esc_html_e( 'Posts, pages, categories and tags urls are not modified.', 'polylang' ); ?></p>
45
+ <label>
46
+ <?php
47
  printf(
48
  '<input name="force_lang" type="radio" value="1" %s/> %s',
49
  1 == $this->options['force_lang'] ? 'checked="checked"' : '',
50
  $this->links_model->using_permalinks ? esc_html__( 'The language is set from the directory name in pretty permalinks', 'polylang' ) : esc_html__( 'The language is set from the code in the URL', 'polylang' )
51
+ );
52
+ ?>
53
  </label>
54
+ <p class="description"><?php echo esc_html__( 'Example:', 'polylang' ) . ' <code>' . esc_html( home_url( $this->links_model->using_permalinks ? 'en/my-post/' : '?lang=en&p=1' ) ) . '</code>'; ?></p>
55
+ <label>
56
+ <?php
57
  printf(
58
  '<input name="force_lang" type="radio" value="2" %s %s/> %s',
59
  $this->links_model->using_permalinks ? '' : 'disabled="disabled"',
60
  2 == $this->options['force_lang'] ? 'checked="checked"' : '',
61
  esc_html__( 'The language is set from the subdomain name in pretty permalinks', 'polylang' )
62
+ );
63
+ ?>
64
  </label>
65
+ <p class="description"><?php echo esc_html__( 'Example:', 'polylang' ) . ' <code>' . esc_html( str_replace( array( '://', 'www.' ), array( '://en.', '' ), home_url( 'my-post/' ) ) ) . '</code>'; ?></p>
66
+ <label>
67
+ <?php
68
  printf(
69
  '<input name="force_lang" type="radio" value="3" %s %s/> %s',
70
  $this->links_model->using_permalinks ? '' : 'disabled="disabled"',
71
  3 == $this->options['force_lang'] ? 'checked="checked"' : '',
72
  esc_html__( 'The language is set from different domains', 'polylang' )
73
+ );
74
+ ?>
75
  </label>
76
+ <table id="pll-domains-table" class="form-table" <?php echo 3 == $this->options['force_lang'] ? '' : 'style="display: none;"'; ?>>
77
+ <?php
78
  foreach ( $this->model->get_languages_list() as $lg ) {
79
  printf(
80
  '<tr><td><label for="pll-domain[%1$s]">%2$s</label></td>' .
83
  esc_attr( $lg->name ),
84
  esc_url( isset( $this->options['domains'][ $lg->slug ] ) ? $this->options['domains'][ $lg->slug ] : ( $lg->slug == $this->options['default_lang'] ? $this->links_model->home : '' ) )
85
  );
86
+ }
87
+ ?>
88
+ </table>
89
+ <?php
90
  }
91
 
92
  /**
94
  *
95
  * @since 1.8
96
  */
97
+ protected function hide_default() {
98
+ ?>
99
+ <label>
100
+ <?php
101
  printf(
102
  '<input name="hide_default" type="checkbox" value="1" %s /> %s',
103
+ $this->options['hide_default'] ? 'checked="checked"' : '',
104
  esc_html__( 'Hide URL language information for default language', 'polylang' )
105
+ );
106
+ ?>
107
+ </label>
108
+ <?php
109
  }
110
 
111
  /**
113
  *
114
  * @since 1.8
115
  */
116
+ protected function rewrite() {
117
+ ?>
118
+ <label>
119
+ <?php
120
  printf(
121
  '<input name="rewrite" type="radio" value="1" %s %s/> %s',
122
  $this->links_model->using_permalinks ? '' : 'disabled="disabled"',
123
  $this->options['rewrite'] ? 'checked="checked"' : '',
124
  esc_html__( 'Remove /language/ in pretty permalinks', 'polylang' )
125
+ );
126
+ ?>
127
  </label>
128
+ <p class="description"><?php echo esc_html__( 'Example:', 'polylang' ) . ' <code>' . esc_html( home_url( 'en/' ) ) . '</code>'; ?></p>
129
+ <label>
130
+ <?php
131
  printf(
132
  '<input name="rewrite" type="radio" value="0" %s %s/> %s',
133
  $this->links_model->using_permalinks ? '' : 'disabled="disabled"',
134
  $this->options['rewrite'] ? '' : 'checked="checked"',
135
  esc_html__( 'Keep /language/ in pretty permalinks', 'polylang' )
136
+ );
137
+ ?>
138
  </label>
139
+ <p class="description"><?php echo esc_html__( 'Example:', 'polylang' ) . ' <code>' . esc_html( home_url( 'language/en/' ) ) . '</code>'; ?></p>
140
+ <?php
141
  }
142
 
143
  /**
145
  *
146
  * @since 1.8
147
  */
148
+ protected function redirect_lang() {
149
+ ?>
150
+ <label>
151
+ <?php
152
  printf(
153
  '<input name="redirect_lang" type="checkbox" value="1" %s/> %s',
154
+ $this->options['redirect_lang'] ? 'checked="checked"' : '',
155
  esc_html__( 'The front page url contains the language code instead of the page name or page id', 'polylang' )
156
+ );
157
+ ?>
158
  </label>
159
+ <p class="description">
160
+ <?php
161
  // That's nice to display the right home urls but don't forget that the page on front may have no language yet
162
  $lang = $this->model->post->get_language( $this->page_on_front );
163
  $lang = $lang ? $lang : $this->model->get_language( $this->options['default_lang'] );
166
  esc_html__( 'Example: %s instead of %s', 'polylang' ),
167
  '<code>' . esc_html( $this->links_model->home_url( $lang ) ) . '</code>',
168
  '<code>' . esc_html( _get_page_link( $this->page_on_front ) ) . '</code>'
169
+ );
170
+ ?>
171
+ </p>
172
+ <?php
173
  }
174
 
175
  /**
177
  *
178
  * @since 1.8
179
  */
180
+ public function form() {
181
+ ?>
182
  <div class="pll-settings-url-col">
183
+ <fieldset class="pll-col-left pll-url" id="pll-force-lang">
184
+ <?php $this->force_lang(); ?>
185
  </fieldset>
186
  </div>
187
 
188
  <div class="pll-settings-url-col">
189
+ <fieldset class="pll-col-right pll-url" id="pll-hide-default" <?php echo 3 > $this->options['force_lang'] ? '' : 'style="display: none;"'; ?>>
190
+ <?php $this->hide_default(); ?>
191
+ </fieldset>
192
+ <?php
193
+ if ( $this->links_model->using_permalinks ) {
194
+ ?>
195
+ <fieldset class="pll-col-right pll-url" id="pll-rewrite" <?php echo 2 > $this->options['force_lang'] ? '' : 'style="display: none;"'; ?>>
196
+ <?php $this->rewrite(); ?>
197
+ </fieldset>
198
+ <?php
199
  }
200
 
201
+ if ( $this->page_on_front ) {
202
+ ?>
203
+ <fieldset class="pll-col-right pll-url" id="pll-redirect-lang" <?php echo 2 > $this->options['force_lang'] ? '' : 'style="display: none;"'; ?>>
204
+ <?php $this->redirect_lang(); ?>
205
+ </fieldset>
206
+ <?php
207
+ }
208
+ ?>
209
+ </div>
210
+ <?php
211
  }
212
 
213
  /**
242
  }
243
 
244
  if ( 3 == $options['force_lang'] ) {
245
+ if ( ! class_exists( 'PLL_Xdata_Domain', true ) ) {
246
+ $newoptions['browser'] = 0;
247
+ }
248
+ $newoptions['hide_default'] = 0;
249
  }
250
 
251
  // Check if domains exist
settings/settings.php CHANGED
@@ -137,9 +137,9 @@ class PLL_Settings extends PLL_Admin_Base {
137
  *
138
  * @since 0.9.5
139
  *
140
- * @param mixed $status false or value returned by previous filter
141
- * @param string $option Name of the option being changed
142
- * @param string $value Value of the option
143
  *
144
  * @return string New value if this is our option, otherwise nothing
145
  */
@@ -171,7 +171,7 @@ class PLL_Settings extends PLL_Admin_Base {
171
  wp_clean_plugins_cache();
172
  }
173
  self::redirect(); // to refresh the page ( possible thanks to the $_GET['noheader']=true )
174
- break;
175
 
176
  case 'delete':
177
  check_admin_referer( 'delete-lang' );
@@ -181,13 +181,13 @@ class PLL_Settings extends PLL_Admin_Base {
181
  }
182
 
183
  self::redirect(); // to refresh the page ( possible thanks to the $_GET['noheader']=true )
184
- break;
185
 
186
  case 'update':
187
  check_admin_referer( 'add-lang', '_wpnonce_add-lang' );
188
  $error = $this->model->update_language( $_POST );
189
  self::redirect(); // to refresh the page ( possible thanks to the $_GET['noheader']=true )
190
- break;
191
 
192
  case 'default-lang':
193
  check_admin_referer( 'default-lang' );
@@ -197,7 +197,7 @@ class PLL_Settings extends PLL_Admin_Base {
197
  }
198
 
199
  self::redirect(); // to refresh the page ( possible thanks to the $_GET['noheader']=true )
200
- break;
201
 
202
  case 'content-default-lang':
203
  check_admin_referer( 'content-default-lang' );
@@ -212,19 +212,19 @@ class PLL_Settings extends PLL_Admin_Base {
212
  }
213
 
214
  self::redirect(); // to refresh the page ( possible thanks to the $_GET['noheader']=true )
215
- break;
216
 
217
  case 'activate':
218
  check_admin_referer( 'pll_activate' );
219
  $this->modules[ $_GET['module'] ]->activate();
220
  self::redirect();
221
- break;
222
 
223
  case 'deactivate':
224
  check_admin_referer( 'pll_deactivate' );
225
  $this->modules[ $_GET['module'] ]->deactivate();
226
  self::redirect();
227
- break;
228
 
229
  default:
230
  /**
@@ -233,7 +233,7 @@ class PLL_Settings extends PLL_Admin_Base {
233
  * @since 1.8
234
  */
235
  do_action( "mlang_action_$action" );
236
- break;
237
  }
238
  }
239
 
@@ -249,12 +249,12 @@ class PLL_Settings extends PLL_Admin_Base {
249
  // prepare the list table of languages
250
  $list_table = new PLL_Table_Languages();
251
  $list_table->prepare_items( $this->model->get_languages_list() );
252
- break;
253
 
254
  case 'strings':
255
  $string_table = new PLL_Table_String( $this->model->get_languages_list() );
256
  $string_table->prepare_items();
257
- break;
258
  }
259
 
260
  // handle user input
137
  *
138
  * @since 0.9.5
139
  *
140
+ * @param mixed $status false or value returned by previous filter
141
+ * @param string $option Name of the option being changed
142
+ * @param string $value Value of the option
143
  *
144
  * @return string New value if this is our option, otherwise nothing
145
  */
171
  wp_clean_plugins_cache();
172
  }
173
  self::redirect(); // to refresh the page ( possible thanks to the $_GET['noheader']=true )
174
+ break;
175
 
176
  case 'delete':
177
  check_admin_referer( 'delete-lang' );
181
  }
182
 
183
  self::redirect(); // to refresh the page ( possible thanks to the $_GET['noheader']=true )
184
+ break;
185
 
186
  case 'update':
187
  check_admin_referer( 'add-lang', '_wpnonce_add-lang' );
188
  $error = $this->model->update_language( $_POST );
189
  self::redirect(); // to refresh the page ( possible thanks to the $_GET['noheader']=true )
190
+ break;
191
 
192
  case 'default-lang':
193
  check_admin_referer( 'default-lang' );
197
  }
198
 
199
  self::redirect(); // to refresh the page ( possible thanks to the $_GET['noheader']=true )
200
+ break;
201
 
202
  case 'content-default-lang':
203
  check_admin_referer( 'content-default-lang' );
212
  }
213
 
214
  self::redirect(); // to refresh the page ( possible thanks to the $_GET['noheader']=true )
215
+ break;
216
 
217
  case 'activate':
218
  check_admin_referer( 'pll_activate' );
219
  $this->modules[ $_GET['module'] ]->activate();
220
  self::redirect();
221
+ break;
222
 
223
  case 'deactivate':
224
  check_admin_referer( 'pll_deactivate' );
225
  $this->modules[ $_GET['module'] ]->deactivate();
226
  self::redirect();
227
+ break;
228
 
229
  default:
230
  /**
233
  * @since 1.8
234
  */
235
  do_action( "mlang_action_$action" );
236
+ break;
237
  }
238
  }
239
 
249
  // prepare the list table of languages
250
  $list_table = new PLL_Table_Languages();
251
  $list_table->prepare_items( $this->model->get_languages_list() );
252
+ break;
253
 
254
  case 'strings':
255
  $string_table = new PLL_Table_String( $this->model->get_languages_list() );
256
  $string_table->prepare_items();
257
+ break;
258
  }
259
 
260
  // handle user input
settings/table-languages.php CHANGED
@@ -19,8 +19,8 @@ class PLL_Table_Languages extends WP_List_Table {
19
  */
20
  function __construct() {
21
  parent::__construct( array(
22
- 'plural' => 'Languages', // Do not translate ( used for css class )
23
- 'ajax' => false,
24
  ) );
25
  }
26
 
@@ -160,11 +160,11 @@ class PLL_Table_Languages extends WP_List_Table {
160
  */
161
  function get_sortable_columns() {
162
  return array(
163
- 'name' => array( 'name', true ), // sorted by name by default
164
- 'locale' => array( 'locale', false ),
165
- 'slug' => array( 'slug', false ),
166
- 'term_group' => array( 'term_group', false ),
167
- 'count' => array( 'count', false ),
168
  );
169
  }
170
 
@@ -262,7 +262,7 @@ class PLL_Table_Languages extends WP_List_Table {
262
 
263
  $this->set_pagination_args( array(
264
  'total_items' => $total_items,
265
- 'per_page' => $per_page,
266
  'total_pages' => ceil( $total_items / $per_page ),
267
  ) );
268
  }
19
  */
20
  function __construct() {
21
  parent::__construct( array(
22
+ 'plural' => 'Languages', // Do not translate ( used for css class )
23
+ 'ajax' => false,
24
  ) );
25
  }
26
 
160
  */
161
  function get_sortable_columns() {
162
  return array(
163
+ 'name' => array( 'name', true ), // sorted by name by default
164
+ 'locale' => array( 'locale', false ),
165
+ 'slug' => array( 'slug', false ),
166
+ 'term_group' => array( 'term_group', false ),
167
+ 'count' => array( 'count', false ),
168
  );
169
  }
170
 
262
 
263
  $this->set_pagination_args( array(
264
  'total_items' => $total_items,
265
+ 'per_page' => $per_page,
266
  'total_pages' => ceil( $total_items / $per_page ),
267
  ) );
268
  }
settings/table-settings.php CHANGED
@@ -18,8 +18,8 @@ class PLL_Table_Settings extends WP_List_Table {
18
  */
19
  function __construct() {
20
  parent::__construct( array(
21
- 'plural' => 'Settings', // Do not translate ( used for css class )
22
- 'ajax' => false,
23
  ) );
24
  }
25
 
18
  */
19
  function __construct() {
20
  parent::__construct( array(
21
+ 'plural' => 'Settings', // Do not translate ( used for css class )
22
+ 'ajax' => false,
23
  ) );
24
  }
25
 
settings/table-string.php CHANGED
@@ -22,8 +22,8 @@ class PLL_Table_String extends WP_List_Table {
22
  */
23
  function __construct( $languages ) {
24
  parent::__construct( array(
25
- 'plural' => 'Strings translations', // Do not translate ( used for css class )
26
- 'ajax' => false,
27
  ) );
28
 
29
  $this->languages = $languages;
@@ -93,7 +93,7 @@ class PLL_Table_String extends WP_List_Table {
93
  $input_type = $item['multiline'] ?
94
  '<textarea name="translation[%1$s][%2$s]" id="%1$s-%2$s">%4$s</textarea>' :
95
  '<input type="text" name="translation[%1$s][%2$s]" id="%1$s-%2$s" value="%4$s" />';
96
- $out .= sprintf( '<div class="translation"><label for="%1$s-%2$s">%3$s</label>'.$input_type.'</div>'."\n",
97
  esc_attr( $key ),
98
  esc_attr( $item['row'] ),
99
  esc_html( $languages[ $key ] ),
@@ -203,7 +203,7 @@ class PLL_Table_String extends WP_List_Table {
203
 
204
  $this->set_pagination_args( array(
205
  'total_items' => $total_items,
206
- 'per_page' => $per_page,
207
  'total_pages' => ceil( $total_items / $per_page ),
208
  ) );
209
  }
@@ -264,7 +264,7 @@ class PLL_Table_String extends WP_List_Table {
264
  esc_html( $group )
265
  );
266
  }
267
- echo '</select>'."\n";
268
 
269
  submit_button( __( 'Filter' ), 'button', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
270
  echo '</div>';
22
  */
23
  function __construct( $languages ) {
24
  parent::__construct( array(
25
+ 'plural' => 'Strings translations', // Do not translate ( used for css class )
26
+ 'ajax' => false,
27
  ) );
28
 
29
  $this->languages = $languages;
93
  $input_type = $item['multiline'] ?
94
  '<textarea name="translation[%1$s][%2$s]" id="%1$s-%2$s">%4$s</textarea>' :
95
  '<input type="text" name="translation[%1$s][%2$s]" id="%1$s-%2$s" value="%4$s" />';
96
+ $out .= sprintf( '<div class="translation"><label for="%1$s-%2$s">%3$s</label>' . $input_type . '</div>' . "\n",
97
  esc_attr( $key ),
98
  esc_attr( $item['row'] ),
99
  esc_html( $languages[ $key ] ),
203
 
204
  $this->set_pagination_args( array(
205
  'total_items' => $total_items,
206
+ 'per_page' => $per_page,
207
  'total_pages' => ceil( $total_items / $per_page ),
208
  ) );
209
  }
264
  esc_html( $group )
265
  );
266
  }
267
+ echo '</select>' . "\n";
268
 
269
  submit_button( __( 'Filter' ), 'button', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
270
  echo '</div>';
settings/view-about.php CHANGED
@@ -1,35 +1,40 @@
1
  <?php
2
 
3
  /**
4
- * displays the content of the About metabox
5
  */
6
 
7
  if ( ! defined( 'ABSPATH' ) ) {
8
- exit; // don't access directly
9
  };
10
  ?>
11
- <p><?php
12
- printf(
13
- /* translators: %s are html tags */
14
- esc_html__( 'Polylang is provided with an extensive %sdocumentation%s (in English only). It includes information on how to set up your multilingual site and use it on a daily basis, a FAQ, as well as a documentation for developers to adapt their plugins and themes.', 'polylang' ),
15
- '<a href="https://polylang.pro/doc/">',
16
- '</a>'
17
- );
18
- if ( ! defined( 'POLYLANG_PRO' ) ) {
19
- echo ' ';
20
  printf(
21
  /* translators: %s are html tags */
22
- esc_html__( 'Support and extra features are available to %sPolylang Pro%s users.' ),
23
- '<a href="https://polylang.pro">',
24
  '</a>'
25
  );
26
- }?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  </p>
28
- <p><?php
29
- printf(
30
- /* translators: %s are html tags */
31
- esc_html__( 'Polylang is released under the same license as WordPress, the %sGPL%s.', 'polylang' ),
32
- '<a href="http://wordpress.org/about/gpl/">',
33
- '</a>'
34
- );
35
 
1
  <?php
2
 
3
  /**
4
+ * Displays the content of the About metabox
5
  */
6
 
7
  if ( ! defined( 'ABSPATH' ) ) {
8
+ exit; // Don't access directly
9
  };
10
  ?>
11
+ <p>
12
+ <?php
 
 
 
 
 
 
 
13
  printf(
14
  /* translators: %s are html tags */
15
+ esc_html__( 'Polylang is provided with an extensive %sdocumentation%s (in English only). It includes information on how to set up your multilingual site and use it on a daily basis, a FAQ, as well as a documentation for developers to adapt their plugins and themes.', 'polylang' ),
16
+ '<a href="https://polylang.pro/doc/">',
17
  '</a>'
18
  );
19
+ if ( ! defined( 'POLYLANG_PRO' ) ) {
20
+ echo ' ';
21
+ printf(
22
+ /* translators: %s are html tags */
23
+ esc_html__( 'Support and extra features are available to %sPolylang Pro%s users.' ),
24
+ '<a href="https://polylang.pro">',
25
+ '</a>'
26
+ );
27
+ }
28
+ ?>
29
+ </p>
30
+ <p>
31
+ <?php
32
+ printf(
33
+ /* translators: %s are html tags */
34
+ esc_html__( 'Polylang is released under the same license as WordPress, the %sGPL%s.', 'polylang' ),
35
+ '<a href="http://wordpress.org/about/gpl/">',
36
+ '</a>'
37
+ );
38
+ ?>
39
  </p>
 
 
 
 
 
 
 
40
 
settings/view-languages.php CHANGED
@@ -11,14 +11,14 @@ if ( ! defined( 'ABSPATH' ) ) {
11
  require ABSPATH . 'wp-admin/options-head.php'; // Displays the errors messages as when we were a child of options-general.php
12
  ?>
13
  <div class="wrap">
14
- <h1><?php echo esc_html( $GLOBALS['title'] ); ?></h1><?php
15
-
16
  switch ( $this->active_tab ) {
17
  case 'lang': // Languages tab
18
  case 'strings': // String translations tab
19
  case 'settings': // Settings tab
20
  include PLL_SETTINGS_INC . '/view-tab-' . $this->active_tab . '.php';
21
- break;
22
 
23
  default:
24
  /**
@@ -28,7 +28,7 @@ require ABSPATH . 'wp-admin/options-head.php'; // Displays the errors messages a
28
  * @since 1.5.1
29
  */
30
  do_action( 'pll_settings_active_tab_' . $this->active_tab );
31
- break;
32
- }?>
33
-
34
  </div><!-- wrap -->
11
  require ABSPATH . 'wp-admin/options-head.php'; // Displays the errors messages as when we were a child of options-general.php
12
  ?>
13
  <div class="wrap">
14
+ <h1><?php echo esc_html( $GLOBALS['title'] ); ?></h1>
15
+ <?php
16
  switch ( $this->active_tab ) {
17
  case 'lang': // Languages tab
18
  case 'strings': // String translations tab
19
  case 'settings': // Settings tab
20
  include PLL_SETTINGS_INC . '/view-tab-' . $this->active_tab . '.php';
21
+ break;
22
 
23
  default:
24
  /**
28
  * @since 1.5.1
29
  */
30
  do_action( 'pll_settings_active_tab_' . $this->active_tab );
31
+ break;
32
+ }
33
+ ?>
34
  </div><!-- wrap -->
settings/view-tab-lang.php CHANGED
@@ -10,12 +10,16 @@ if ( ! defined( 'ABSPATH' ) ) {
10
  ?>
11
  <div id="col-container">
12
  <div id="col-right">
13
- <div class="col-wrap"><?php
14
- // displays the language list in a table
15
- $list_table->display();?>
16
- <div class="metabox-holder"><?php
 
 
 
17
  wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
18
- do_meta_boxes( 'settings_page_mlang', 'normal', array() );?>
 
19
  </div>
20
  </div><!-- col-wrap -->
21
  </div><!-- col-right -->
@@ -24,68 +28,83 @@ if ( ! defined( 'ABSPATH' ) ) {
24
  <div class="col-wrap">
25
 
26
  <div class="form-wrap">
27
- <h3><?php echo ! empty( $edit_lang ) ? esc_html__( 'Edit language', 'polylang' ) : esc_html__( 'Add new language', 'polylang' ); ?></h3><?php
28
-
29
- // displays the add ( or edit ) language form
30
- // adds noheader=true in the action url to allow using wp_redirect when processing the form ?>
31
- <form id="add-lang" method="post" action="admin.php?page=mlang&amp;noheader=true" class="validate"><?php
 
 
32
  wp_nonce_field( 'add-lang', '_wpnonce_add-lang' );
33
 
34
- if ( ! empty( $edit_lang ) ) {?>
 
35
  <input type="hidden" name="pll_action" value="update" />
36
- <input type="hidden" name="lang_id" value="<?php echo esc_attr( $edit_lang->term_id );?>" /><?php
37
- } else { ?>
38
- <input type="hidden" name="pll_action" value="add" /><?php
39
- }?>
40
-
 
 
 
41
  <div class="form-field">
42
- <label for="lang_list"><?php esc_html_e( 'Choose a language', 'polylang' );?></label>
43
  <select name="lang_list" id="lang_list">
44
- <option value=""></option><?php
 
45
  include PLL_SETTINGS_INC . '/languages.php';
46
  foreach ( $languages as $lg ) {
47
  printf(
48
- '<option value="%1$s:%2$s:%3$s:%4$s">%5$s - %2$s</option>'."\n",
49
  esc_attr( $lg[0] ),
50
  esc_attr( $lg[1] ),
51
  'rtl' == $lg[3] ? '1' : '0',
52
  esc_attr( $lg[4] ),
53
  esc_html( $lg[2] )
54
  );
55
- } ?>
 
56
  </select>
57
- <p><?php esc_html_e( 'You can choose a language in the list or directly edit it below.', 'polylang' );?></p>
58
  </div>
59
 
60
  <div class="form-field form-required">
61
- <label for="lang_name"><?php esc_html_e( 'Full name', 'polylang' );?></label><?php
 
62
  printf(
63
  '<input name="name" id="lang_name" type="text" value="%s" size="40" aria-required="true" />',
64
  ! empty( $edit_lang ) ? esc_attr( $edit_lang->name ) : ''
65
- );?>
66
- <p><?php esc_html_e( 'The name is how it is displayed on your site (for example: English).', 'polylang' );?></p>
 
67
  </div>
68
 
69
  <div class="form-field form-required">
70
- <label for="lang_locale"><?php esc_html_e( 'Locale', 'polylang' );?></label><?php
 
71
  printf(
72
  '<input name="locale" id="lang_locale" type="text" value="%s" size="40" aria-required="true" />',
73
  ! empty( $edit_lang ) ? esc_attr( $edit_lang->locale ) : ''
74
- );?>
75
- <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>
 
76
  </div>
77
 
78
  <div class="form-field">
79
- <label for="lang_slug"><?php esc_html_e( 'Language code', 'polylang' );?></label><?php
 
80
  printf(
81
  '<input name="slug" id="lang_slug" type="text" value="%s" size="40"/>',
82
  ! empty( $edit_lang ) ? esc_attr( $edit_lang->slug ) : ''
83
- );?>
84
- <p><?php esc_html_e( 'Language code - preferably 2-letters ISO 639-1 (for example: en)', 'polylang' );?></p>
 
85
  </div>
86
 
87
  <div class="form-field"><fieldset>
88
- <legend><?php esc_html_e( 'Text direction', 'polylang' );?></legend><?php
 
89
  printf(
90
  '<label><input name="rtl" type="radio" value="0" %s /> %s</label>',
91
  ! empty( $edit_lang ) && $edit_lang->is_rtl ? '' : 'checked="checked"',
@@ -95,36 +114,41 @@ if ( ! defined( 'ABSPATH' ) ) {
95
  '<label><input name="rtl" type="radio" value="1" %s /> %s</label>',
96
  ! empty( $edit_lang ) && $edit_lang->is_rtl ? 'checked="checked"' : '',
97
  esc_html__( 'right to left', 'polylang' )
98
- );?>
99
- <p><?php esc_html_e( 'Choose the text direction for the language', 'polylang' );?></p>
 
100
  </fieldset></div>
101
 
102
  <div class="form-field">
103
- <label for="flag_list"><?php esc_html_e( 'Flag', 'polylang' );?></label>
104
  <select name="flag" id="flag_list">
105
- <option value=""></option><?php
 
106
  include PLL_SETTINGS_INC . '/flags.php';
107
  foreach ( $flags as $code => $label ) {
108
  printf(
109
- '<option value="%1$s"%2$s>%3$s</option>'."\n",
110
  esc_attr( $code ),
111
  isset( $edit_lang->flag_code ) && $edit_lang->flag_code == $code ? ' selected="selected"' : '',
112
  esc_html( $label )
113
  );
114
- } ?>
 
115
  </select>
116
- <p><?php esc_html_e( 'Choose a flag for the language.', 'polylang' );?></p>
117
  </div>
118
 
119
  <div class="form-field">
120
- <label for="lang_order"><?php esc_html_e( 'Order', 'polylang' );?></label><?php
 
121
  printf(
122
  '<input name="term_group" id="lang_order" type="text" value="%d" />',
123
  ! empty( $edit_lang ) ? esc_attr( $edit_lang->term_group ) : ''
124
- );?>
125
- <p><?php esc_html_e( 'Position of the language in the language switcher', 'polylang' );?></p>
126
- </div><?php
127
-
 
128
  if ( ! empty( $edit_lang ) ) {
129
  /**
130
  * Fires after the Edit Language form fields are displayed.
@@ -143,8 +167,8 @@ if ( ! defined( 'ABSPATH' ) ) {
143
  do_action( 'pll_language_add_form_fields' );
144
  }
145
 
146
- submit_button( ! empty( $edit_lang ) ? __( 'Update' ) : __( 'Add new language', 'polylang' ) ); // since WP 3.1 ?>
147
-
148
  </form>
149
  </div><!-- form-wrap -->
150
  </div><!-- col-wrap -->
10
  ?>
11
  <div id="col-container">
12
  <div id="col-right">
13
+ <div class="col-wrap">
14
+ <?php
15
+ // Displays the language list in a table
16
+ $list_table->display();
17
+ ?>
18
+ <div class="metabox-holder">
19
+ <?php
20
  wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
21
+ do_meta_boxes( 'settings_page_mlang', 'normal', array() );
22
+ ?>
23
  </div>
24
  </div><!-- col-wrap -->
25
  </div><!-- col-right -->
28
  <div class="col-wrap">
29
 
30
  <div class="form-wrap">
31
+ <h3><?php echo ! empty( $edit_lang ) ? esc_html__( 'Edit language', 'polylang' ) : esc_html__( 'Add new language', 'polylang' ); ?></h3>
32
+ <?php
33
+ // Displays the add ( or edit ) language form
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
+ ?>
42
  <input type="hidden" name="pll_action" value="update" />
43
+ <input type="hidden" name="lang_id" value="<?php echo esc_attr( $edit_lang->term_id ); ?>" />
44
+ <?php
45
+ } else {
46
+ ?>
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
  include PLL_SETTINGS_INC . '/languages.php';
57
  foreach ( $languages as $lg ) {
58
  printf(
59
+ '<option value="%1$s:%2$s:%3$s:%4$s">%5$s - %2$s</option>' . "\n",
60
  esc_attr( $lg[0] ),
61
  esc_attr( $lg[1] ),
62
  'rtl' == $lg[3] ? '1' : '0',
63
  esc_attr( $lg[4] ),
64
  esc_html( $lg[2] )
65
  );
66
+ }
67
+ ?>
68
  </select>
69
+ <p><?php esc_html_e( 'You can choose a language in the list or directly edit it below.', 'polylang' ); ?></p>
70
  </div>
71
 
72
  <div class="form-field form-required">
73
+ <label for="lang_name"><?php esc_html_e( 'Full name', 'polylang' ); ?></label>
74
+ <?php
75
  printf(
76
  '<input name="name" id="lang_name" type="text" value="%s" size="40" aria-required="true" />',
77
  ! empty( $edit_lang ) ? esc_attr( $edit_lang->name ) : ''
78
+ );
79
+ ?>
80
+ <p><?php esc_html_e( 'The name is how it is displayed on your site (for example: English).', 'polylang' ); ?></p>
81
  </div>
82
 
83
  <div class="form-field form-required">
84
+ <label for="lang_locale"><?php esc_html_e( 'Locale', 'polylang' ); ?></label>
85
+ <?php
86
  printf(
87
  '<input name="locale" id="lang_locale" type="text" value="%s" size="40" aria-required="true" />',
88
  ! empty( $edit_lang ) ? esc_attr( $edit_lang->locale ) : ''
89
+ );
90
+ ?>
91
+ <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>
92
  </div>
93
 
94
  <div class="form-field">
95
+ <label for="lang_slug"><?php esc_html_e( 'Language code', 'polylang' ); ?></label>
96
+ <?php
97
  printf(
98
  '<input name="slug" id="lang_slug" type="text" value="%s" size="40"/>',
99
  ! empty( $edit_lang ) ? esc_attr( $edit_lang->slug ) : ''
100
+ );
101
+ ?>
102
+ <p><?php esc_html_e( 'Language code - preferably 2-letters ISO 639-1 (for example: en)', 'polylang' ); ?></p>
103
  </div>
104
 
105
  <div class="form-field"><fieldset>
106
+ <legend><?php esc_html_e( 'Text direction', 'polylang' ); ?></legend>
107
+ <?php
108
  printf(
109
  '<label><input name="rtl" type="radio" value="0" %s /> %s</label>',
110
  ! empty( $edit_lang ) && $edit_lang->is_rtl ? '' : 'checked="checked"',
114
  '<label><input name="rtl" type="radio" value="1" %s /> %s</label>',
115
  ! empty( $edit_lang ) && $edit_lang->is_rtl ? 'checked="checked"' : '',
116
  esc_html__( 'right to left', 'polylang' )
117
+ );
118
+ ?>
119
+ <p><?php esc_html_e( 'Choose the text direction for the language', 'polylang' ); ?></p>
120
  </fieldset></div>
121
 
122
  <div class="form-field">
123
+ <label for="flag_list"><?php esc_html_e( 'Flag', 'polylang' ); ?></label>
124
  <select name="flag" id="flag_list">
125
+ <option value=""></option>
126
+ <?php
127
  include PLL_SETTINGS_INC . '/flags.php';
128
  foreach ( $flags as $code => $label ) {
129
  printf(
130
+ '<option value="%1$s"%2$s>%3$s</option>' . "\n",
131
  esc_attr( $code ),
132
  isset( $edit_lang->flag_code ) && $edit_lang->flag_code == $code ? ' selected="selected"' : '',
133
  esc_html( $label )
134
  );
135
+ }
136
+ ?>
137
  </select>
138
+ <p><?php esc_html_e( 'Choose a flag for the language.', 'polylang' ); ?></p>
139
  </div>
140
 
141
  <div class="form-field">
142
+ <label for="lang_order"><?php esc_html_e( 'Order', 'polylang' ); ?></label>
143
+ <?php
144
  printf(
145
  '<input name="term_group" id="lang_order" type="text" value="%d" />',
146
  ! empty( $edit_lang ) ? esc_attr( $edit_lang->term_group ) : ''
147
+ );
148
+ ?>
149
+ <p><?php esc_html_e( 'Position of the language in the language switcher', 'polylang' ); ?></p>
150
+ </div>
151
+ <?php
152
  if ( ! empty( $edit_lang ) ) {
153
  /**
154
  * Fires after the Edit Language form fields are displayed.
167
  do_action( 'pll_language_add_form_fields' );
168
  }
169
 
170
+ submit_button( ! empty( $edit_lang ) ? __( 'Update' ) : __( 'Add new language', 'polylang' ) ); // since WP 3.1
171
+ ?>
172
  </form>
173
  </div><!-- form-wrap -->
174
  </div><!-- col-wrap -->
settings/view-tab-settings.php CHANGED
@@ -8,9 +8,11 @@ if ( ! defined( 'ABSPATH' ) ) {
8
  exit; // don't access directly
9
  };
10
  ?>
11
- <div class="form-wrap"><?php
 
12
  wp_nonce_field( 'pll_options', '_pll_nonce' );
13
  $list_table = new PLL_Table_Settings();
14
  $list_table->prepare_items( $this->modules );
15
- $list_table->display(); ?>
 
16
  </div>
8
  exit; // don't access directly
9
  };
10
  ?>
11
+ <div class="form-wrap">
12
+ <?php
13
  wp_nonce_field( 'pll_options', '_pll_nonce' );
14
  $list_table = new PLL_Table_Settings();
15
  $list_table->prepare_items( $this->modules );
16
+ $list_table->display();
17
+ ?>
18
  </div>
settings/view-tab-strings.php CHANGED
@@ -1,21 +1,25 @@
1
  <?php
2
 
3
  /**
4
- * displays the strings translations tab in Polylang settings
5
  */
6
 
7
  if ( ! defined( 'ABSPATH' ) ) {
8
- exit; // don't access directly
9
  };
10
  ?>
11
  <div class="form-wrap">
12
  <form id="string-translation" method="post" action="<?php echo esc_url( add_query_arg( 'noheader', 'true' ) ); ?>">
13
- <input type="hidden" name="pll_action" value="string-translation" /><?php
 
14
  $string_table->search_box( __( 'Search translations', 'polylang' ), 'translations' );
15
  wp_nonce_field( 'string-translation', '_wpnonce_string-translation' );
16
  $string_table->display();
17
- printf( '<br /><label><input name="clean" type="checkbox" value="1" /> %s</label>', esc_html__( 'Clean strings translation database', 'polylang' ) ); ?>
18
- <p><?php esc_html_e( 'Use this to remove unused strings from database, for example after a plugin has been uninstalled.', 'polylang' );?></p><?php
19
- submit_button(); // since WP 3.1 ?>
 
 
 
20
  </form>
21
  </div>
1
  <?php
2
 
3
  /**
4
+ * Displays the strings translations tab in Polylang settings
5
  */
6
 
7
  if ( ! defined( 'ABSPATH' ) ) {
8
+ exit; // Don't access directly
9
  };
10
  ?>
11
  <div class="form-wrap">
12
  <form id="string-translation" method="post" action="<?php echo esc_url( add_query_arg( 'noheader', 'true' ) ); ?>">
13
+ <input type="hidden" name="pll_action" value="string-translation" />
14
+ <?php
15
  $string_table->search_box( __( 'Search translations', 'polylang' ), 'translations' );
16
  wp_nonce_field( 'string-translation', '_wpnonce_string-translation' );
17
  $string_table->display();
18
+ printf( '<br /><label><input name="clean" type="checkbox" value="1" /> %s</label>', esc_html__( 'Clean strings translation database', 'polylang' ) );
19
+ ?>
20
+ <p><?php esc_html_e( 'Use this to remove unused strings from database, for example after a plugin has been uninstalled.', 'polylang' ); ?></p>
21
+ <?php
22
+ submit_button(); // Since WP 3.1
23
+ ?>
24
  </form>
25
  </div>
uninstall.php CHANGED
@@ -1,7 +1,6 @@
1
  <?php
2
 
3
- // If uninstall not called from WordPress exit
4
- if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
5
  exit();
6
  }
7
 
@@ -115,13 +114,13 @@ class PLL_Uninstall {
115
 
116
  if ( ! empty( $term_ids ) ) {
117
  $term_ids = array_unique( $term_ids );
118
- $wpdb->query( "DELETE FROM $wpdb->terms WHERE term_id IN ( " . implode( ',', $term_ids ) . " )" );
119
- $wpdb->query( "DELETE FROM $wpdb->term_taxonomy WHERE term_id IN ( " . implode( ',', $term_ids ) . " )" );
120
  }
121
 
122
  if ( ! empty( $tt_ids ) ) {
123
  $tt_ids = array_unique( $tt_ids );
124
- $wpdb->query( "DELETE FROM $wpdb->term_relationships WHERE term_taxonomy_id IN ( " . implode( ',', $tt_ids ) . " )" );
125
  }
126
 
127
  // Delete options
@@ -130,7 +129,7 @@ class PLL_Uninstall {
130
  delete_option( 'polylang_wpml_strings' ); // Strings registered with icl_register_string
131
  delete_option( 'polylang_licenses' );
132
 
133
- //Delete transients
134
  delete_transient( 'pll_languages_list' );
135
  delete_transient( 'pll_upgrade_1_4' );
136
  delete_transient( 'pll_translated_slugs' );
1
  <?php
2
 
3
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) { // If uninstall not called from WordPress exit
 
4
  exit();
5
  }
6
 
114
 
115
  if ( ! empty( $term_ids ) ) {
116
  $term_ids = array_unique( $term_ids );
117
+ $wpdb->query( "DELETE FROM $wpdb->terms WHERE term_id IN ( " . implode( ',', $term_ids ) . ' )' );
118
+ $wpdb->query( "DELETE FROM $wpdb->term_taxonomy WHERE term_id IN ( " . implode( ',', $term_ids ) . ' )' );
119
  }
120
 
121
  if ( ! empty( $tt_ids ) ) {
122
  $tt_ids = array_unique( $tt_ids );
123
+ $wpdb->query( "DELETE FROM $wpdb->term_relationships WHERE term_taxonomy_id IN ( " . implode( ',', $tt_ids ) . ' )' );
124
  }
125
 
126
  // Delete options
129
  delete_option( 'polylang_wpml_strings' ); // Strings registered with icl_register_string
130
  delete_option( 'polylang_licenses' );
131
 
132
+ // Delete transients
133
  delete_transient( 'pll_languages_list' );
134
  delete_transient( 'pll_upgrade_1_4' );
135
  delete_transient( 'pll_translated_slugs' );