PluginProbe
Polylang / 3.7.7
Polylang v3.7.7
3.8.10 3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 All 234 releases
← All changes | frontend/choose-lang.php +114 -104 2.9 → 3.7.7 View file →
@@ -8,9 +8,32 @@
8 8 *
9 9 * @since 1.2
10 10 */
11 11 abstract class PLL_Choose_Lang {
12 - public $links_model, $model, $options;
12 + /**
13 + * Stores the plugin options.
14 + *
15 + * @var array
16 + */
17 + public $options;
18 +
19 + /**
20 + * @var PLL_Model
21 + */
22 + public $model;
23 +
24 + /**
25 + * Instance of a child class of PLL_Links_Model.
26 + *
27 + * @var PLL_Links_Model
28 + */
29 + public $links_model;
30 +
31 + /**
32 + * Current language.
33 + *
34 + * @var PLL_Language|null
35 + */
13 36 public $curlang;
14 37
15 38 /**
16 39 * Constructor
@@ -16,9 +39,9 @@
16 39 * Constructor
17 40 *
18 41 * @since 1.2
19 42 *
20 - * @param object $polylang
43 + * @param object $polylang The Polylang object.
21 44 */
22 45 public function __construct( &$polylang ) {
23 46 $this->links_model = &$polylang->links_model;
24 47 $this->model = &$polylang->model;
@@ -32,8 +55,10 @@
32 55 * and setup actions
33 56 * Any child class must call this method if it overrides it
34 57 *
35 58 * @since 1.8
59 + *
60 + * @return void
36 61 */
37 62 public function init() {
38 63 if ( Polylang::is_ajax_on_front() || ! wp_using_themes() ) {
39 64 $this->set_language( empty( $_REQUEST['lang'] ) ? $this->get_preferred_language() : $this->model->get_language( sanitize_key( $_REQUEST['lang'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification
@@ -44,15 +69,15 @@
44 69 add_action( 'wp', array( $this, 'maybe_setcookie' ), 7 );
45 70 }
46 71
47 72 /**
48 - * Writes language cookie
49 - * Loads user defined translations
50 - * Fires the action 'pll_language_defined'
73 + * Sets the current language
74 + * and fires the action 'pll_language_defined'.
51 75 *
52 76 * @since 1.2
53 77 *
54 - * @param object $curlang current language
78 + * @param PLL_Language|false $curlang Current language.
79 + * @return void
55 80 */
56 81 protected function set_language( $curlang ) {
57 82 // Don't set the language a second time
58 83 if ( isset( $this->curlang ) ) {
@@ -60,20 +85,30 @@
60 85 }
61 86
62 87 // Final check in case $curlang has an unexpected value
63 88 // See https://wordpress.org/support/topic/detect-browser-language-sometimes-setting-null-language
64 - $this->curlang = ( $curlang instanceof PLL_Language ) ? $curlang : $this->model->get_language( $this->options['default_lang'] );
89 + if ( ! $curlang instanceof PLL_Language ) {
90 + $curlang = $this->model->get_default_language();
65 91
66 - $GLOBALS['text_direction'] = $this->curlang->is_rtl ? 'rtl' : 'ltr';
67 - wp_styles()->text_direction = $GLOBALS['text_direction'];
92 + if ( ! $curlang instanceof PLL_Language ) {
93 + return;
94 + }
95 + }
68 96
97 + $this->curlang = $curlang;
98 +
99 + $GLOBALS['text_direction'] = $this->curlang->is_rtl ? 'rtl' : 'ltr';
100 + if ( did_action( 'wp_default_styles' ) ) {
101 + wp_styles()->text_direction = $GLOBALS['text_direction'];
102 + }
103 +
69 104 /**
70 - * Fires when the current language is defined
105 + * Fires when the current language is defined.
71 106 *
72 107 * @since 0.9.5
73 108 *
74 - * @param string $slug current language code
75 - * @param object $curlang current language object
109 + * @param string $slug Current language code.
110 + * @param PLL_Language $curlang Current language object.
76 111 */
77 112 do_action( 'pll_language_defined', $this->curlang->slug, $this->curlang );
78 113 }
79 114
@@ -81,8 +116,10 @@
81 116 * Set a cookie to remember the language.
82 117 * Setting PLL_COOKIE to false will disable cookie although it will break some functionalities
83 118 *
84 119 * @since 1.5
120 + *
121 + * @return void
85 122 */
86 123 public function maybe_setcookie() {
87 124 // Don't set cookie in javascript when a cache plugin is active.
88 125 if ( ! pll_is_cache_active() && ! empty( $this->curlang ) && ! is_404() ) {
@@ -94,87 +131,34 @@
94 131 }
95 132 }
96 133
97 134 /**
98 - * Get the preferred language according to the browser preferences
99 - * Code adapted from http://www.thefutureoftheweb.com/blog/use-accept-language-header
135 + * Get the preferred language according to the browser preferences.
100 136 *
101 137 * @since 1.8
102 138 *
103 - * @return string|bool the preferred language slug or false
139 + * @return string|bool The preferred language slug or false.
104 140 */
105 141 public function get_preferred_browser_language() {
106 - $accept_langs = array();
142 + if ( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) {
143 + $accept_langs = PLL_Accept_Languages_Collection::from_accept_language_header( sanitize_text_field( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) );
107 144
108 - if ( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) {
109 - // Break up string into pieces ( languages and q factors )
110 - preg_match_all(
111 - '/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*((?>1|0)(?>\.[0-9]+)?))?/i',
112 - sanitize_text_field( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ),
113 - $lang_parse
114 - );
145 + $accept_langs->bubble_sort();
115 146
116 - $k = $lang_parse[1];
117 - $v = $lang_parse[4];
147 + $languages = $this->model->get_languages_list( array( 'hide_empty' => true ) ); // Hides languages with no post.
118 148
119 - if ( $n = count( $k ) ) {
120 - // Set default to 1 for any without q factor
121 - foreach ( $v as $key => $val ) {
122 - if ( '' === $val || (float) $val > 1 ) {
123 - $v[ $key ] = 1;
124 - }
125 - }
149 + /**
150 + * Filters the list of languages to use to match the browser preferences.
151 + *
152 + * @since 1.9.3
153 + *
154 + * @param array $languages Array of PLL_Language objects.
155 + */
156 + $languages = apply_filters( 'pll_languages_for_browser_preferences', $languages );
126 157
127 - // Bubble sort ( need a stable sort for Android, so can't use a PHP sort function )
128 - if ( $n > 1 ) {
129 - for ( $i = 2; $i <= $n; $i++ ) {
130 - for ( $j = 0; $j <= $n - 2; $j++ ) {
131 - if ( $v[ $j ] < $v[ $j + 1 ] ) {
132 - // Swap values
133 - $temp = $v[ $j ];
134 - $v[ $j ] = $v[ $j + 1 ];
135 - $v[ $j + 1 ] = $temp;
136 - // Swap keys
137 - $temp = $k[ $j ];
138 - $k[ $j ] = $k[ $j + 1 ];
139 - $k[ $j + 1 ] = $temp;
140 - }
141 - }
142 - }
143 - }
144 - $accept_langs = array_combine( $k, $v );
145 - }
158 + return $accept_langs->find_best_match( $languages );
146 159 }
147 160
148 - $accept_langs = array_filter( $accept_langs ); // Remove languages marked as unacceptable (q=0).
149 -
150 - $languages = $this->model->get_languages_list( array( 'hide_empty' => true ) ); // Hides languages with no post
151 -
152 - /**
153 - * Filter the list of languages to use to match the browser preferences
154 - *
155 - * @since 1.9.3
156 - *
157 - * @param array $languages array of PLL_Language objects
158 - */
159 - $languages = apply_filters( 'pll_languages_for_browser_preferences', $languages );
160 -
161 - // Looks through sorted list and use first one that matches our language list
162 - foreach ( array_keys( $accept_langs ) as $accept_lang ) {
163 - // First loop to match the exact locale
164 - foreach ( $languages as $language ) {
165 - if ( 0 === strcasecmp( $accept_lang, $language->get_locale( 'display' ) ) ) {
166 - return $language->slug;
167 - }
168 - }
169 -
170 - // Second loop to match the language set
171 - foreach ( $languages as $language ) {
172 - if ( 0 === stripos( $accept_lang, $language->slug ) || 0 === stripos( $language->get_locale( 'display' ), $accept_lang ) ) {
173 - return $language->slug;
174 - }
175 - }
176 - }
177 161 return false;
178 162 }
179 163
180 164 /**
@@ -184,9 +168,9 @@
184 168 * or the default language
185 169 *
186 170 * @since 0.1
187 171 *
188 - * @return object browser preferred language or default language
172 + * @return PLL_Language|false browser preferred language or default language
189 173 */
190 174 public function get_preferred_language() {
191 175 $language = false;
192 176 $cookie = false;
@@ -213,9 +197,9 @@
213 197 */
214 198 $slug = apply_filters( 'pll_preferred_language', $language, $cookie );
215 199
216 200 // Return default if there is no preferences in the browser or preferences does not match our languages or it is requested not to use the browser preference
217 - return ( $lang = $this->model->get_language( $slug ) ) ? $lang : $this->model->get_language( $this->options['default_lang'] );
201 + return ( $lang = $this->model->get_language( $slug ) ) ? $lang : $this->model->get_default_language();
218 202 }
219 203
220 204 /**
221 205 * Sets the language when home page is requested
@@ -220,14 +204,16 @@
220 204 /**
221 205 * Sets the language when home page is requested
222 206 *
223 207 * @since 1.2
208 + *
209 + * @return void
224 210 */
225 211 protected function home_language() {
226 212 // Test referer in case PLL_COOKIE is set to false. Since WP 3.6.1, wp_get_referer() validates the host which is exactly what we want
227 213 // Thanks to Ov3rfly http://wordpress.org/support/topic/enhance-feature-when-front-page-is-visited-set-language-according-to-browser
228 214 $language = $this->options['hide_default'] && ( wp_get_referer() || ! $this->options['browser'] ) ?
229 - $this->model->get_language( $this->options['default_lang'] ) :
215 + $this->model->get_default_language() :
230 216 $this->get_preferred_language(); // Sets the language according to browser preference or default language
231 217 $this->set_language( $language );
232 218 }
233 219
@@ -236,12 +222,18 @@
236 222 * Make sure to call this after 'setup_theme' has been fired as we need $wp_query
237 223 * Performs a redirection to the home page in the current language if needed
238 224 *
239 225 * @since 0.9
226 + *
227 + * @return void
240 228 */
241 229 public function home_requested() {
230 + if ( empty( $this->curlang ) ) {
231 + return;
232 + }
233 +
242 234 // We are already on the right page
243 - if ( $this->options['default_lang'] == $this->curlang->slug && $this->options['hide_default'] ) {
235 + if ( $this->curlang->is_default && $this->options['hide_default'] ) {
244 236 $this->set_curlang_in_query( $GLOBALS['wp_query'] );
245 237
246 238 /**
247 239 * Fires when the site root page is requested
@@ -253,9 +245,9 @@
253 245 // Redirect to the home page in the right language
254 246 // Test to avoid crash if get_home_url returns something wrong
255 247 // FIXME why this happens? http://wordpress.org/support/topic/polylang-crashes-1
256 248 // Don't redirect if $_POST is not empty as it could break other plugins
257 - elseif ( is_string( $redirect = $this->curlang->home_url ) && empty( $_POST ) ) { // phpcs:ignore WordPress.Security.NonceVerification
249 + elseif ( is_string( $redirect = $this->curlang->get_home_url() ) && empty( $_POST ) ) { // phpcs:ignore WordPress.Security.NonceVerification
258 250 // Don't forget the query string which may be added by plugins
259 251 $query_string = wp_parse_url( pll_get_requested_url(), PHP_URL_QUERY );
260 252 if ( ! empty( $query_string ) ) {
261 253 $redirect .= ( $this->links_model->using_permalinks ? '?' : '&' ) . $query_string;
@@ -269,9 +261,10 @@
269 261 * @since 1.1.1
270 262 *
271 263 * @param string $redirect the url the visitor will be redirected to
272 264 */
273 - if ( $redirect = apply_filters( 'pll_redirect_home', $redirect ) ) {
265 + $redirect = apply_filters( 'pll_redirect_home', $redirect );
266 + if ( $redirect && wp_validate_redirect( $redirect ) ) {
274 267 $this->maybe_setcookie();
275 268 header( 'Vary: Accept-Language' );
276 269 wp_safe_redirect( $redirect, 302, POLYLANG );
277 270 exit;
@@ -284,8 +277,9 @@
284 277 *
285 278 * @since 0.8.4
286 279 *
287 280 * @param int $post_id the post being commented
281 + * @return void
288 282 */
289 283 public function pre_comment_on_post( $post_id ) {
290 284 $this->set_language( $this->model->post->get_language( $post_id ) );
291 285 }
@@ -290,14 +284,15 @@
290 284 $this->set_language( $this->model->post->get_language( $post_id ) );
291 285 }
292 286
293 287 /**
294 - * Modifies some main query vars for home page and page for posts
295 - * to enable one home page ( and one page for posts ) per language
288 + * Modifies some main query vars for the home page and the page for posts
289 + * to enable one home page (and one page for posts) per language.
296 290 *
297 291 * @since 1.2
298 292 *
299 - * @param object $query instance of WP_Query
293 + * @param WP_Query $query Instance of WP_Query.
294 + * @return void
300 295 */
301 296 public function parse_main_query( $query ) {
302 297 if ( ! $query->is_main_query() ) {
303 298 return;
@@ -307,35 +302,50 @@
307 302 * This filter allows to set the language based on information contained in the main query
308 303 *
309 304 * @since 1.8
310 305 *
311 - * @param bool|object $lang false or language object
312 - * @param object $query WP_Query object
306 + * @param PLL_Language|false $lang Language object or false.
307 + * @param WP_Query $query WP_Query object.
313 308 */
314 309 if ( $lang = apply_filters( 'pll_set_language_from_query', false, $query ) ) {
315 310 $this->set_language( $lang );
316 311 $this->set_curlang_in_query( $query );
312 + } elseif ( ( count( $query->query ) == 1 || ( is_paged() && count( $query->query ) == 2 ) ) && $lang = get_query_var( 'lang' ) ) {
313 + $lang = $this->model->get_language( $lang );
314 + $this->set_language( $lang ); // Set the language now otherwise it will be too late to filter sticky posts!
315 +
316 + // Set is_home on translated home page when it displays posts. It must be true on page 2, 3... too.
317 + $query->is_home = true;
318 + $query->is_tax = false;
319 + $query->is_archive = false;
320 +
321 + // Filters is_front_page() in case a static front page is not translated in this language.
322 + add_filter( 'option_show_on_front', array( $this, 'filter_option_show_on_front' ) );
317 323 }
324 + }
318 325
319 - // sets is_home on translated home page when it displays posts
320 - // is_home must be true on page 2, 3... too
321 - // as well as when searching an empty string: http://wordpress.org/support/topic/plugin-polylang-polylang-breaks-search-in-spun-theme
322 - elseif ( ( count( $query->query ) == 1 || ( is_paged() && count( $query->query ) == 2 ) || ( isset( $query->query['s'] ) && ! $query->query['s'] ) ) && $lang = get_query_var( 'lang' ) ) {
323 - $lang = $this->model->get_language( $lang );
324 - $this->set_language( $lang ); // sets the language now otherwise it will be too late to filter sticky posts !
325 - $query->is_home = true;
326 - $query->is_archive = $query->is_tax = false;
327 - }
326 + /**
327 + * Filters the option show_on_front when the current front page displays posts.
328 + *
329 + * This is useful when a static front page is not translated in all languages.
330 + *
331 + * @return string
332 + */
333 + public function filter_option_show_on_front() {
334 + return 'posts';
328 335 }
329 336
330 337 /**
331 - * Sets the current language in the query
338 + * Sets the current language in the query.
332 339 *
333 340 * @since 2.2
334 341 *
335 - * @param object $query
342 + * @param WP_Query $query Instance of WP_Query.
343 + * @return void
336 344 */
337 345 protected function set_curlang_in_query( &$query ) {
338 - $pll_query = new PLL_Query( $query, $this->model );
339 - $pll_query->set_language( $this->curlang );
346 + if ( ! empty( $this->curlang ) ) {
347 + $pll_query = new PLL_Query( $query, $this->model );
348 + $pll_query->set_language( $this->curlang );
349 + }
340 350 }
341 351 }