PluginProbe
Polylang / 3.0.3
Polylang v3.0.3
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 3.0.3 All 233 releases
polylang / frontend / choose-lang.php

choose-lang.php in Polylang 3.0.3, at frontend/choose-lang.php

333 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 /**
7 * Base class to choose the language
8 *
9 * @since 1.2
10 */
11 abstract class PLL_Choose_Lang {
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
35 */
36 public $curlang;
37 /**
38 * @var PLL_Accept_Language
39 */
40 private $lang_parse;
41 /**
42 * @var PLL_Accept_Languages_Collection
43 */
44 private $accept_langs;
45
46 /**
47 * Constructor
48 *
49 * @since 1.2
50 *
51 * @param object $polylang
52 */
53 public function __construct( &$polylang ) {
54 $this->links_model = &$polylang->links_model;
55 $this->model = &$polylang->model;
56 $this->options = &$polylang->options;
57
58 $this->curlang = &$polylang->curlang;
59 }
60
61 /**
62 * Sets the language for ajax requests
63 * and setup actions
64 * Any child class must call this method if it overrides it
65 *
66 * @since 1.8
67 *
68 * @return void
69 */
70 public function init() {
71 if ( Polylang::is_ajax_on_front() || ! wp_using_themes() ) {
72 $this->set_language( empty( $_REQUEST['lang'] ) ? $this->get_preferred_language() : $this->model->get_language( sanitize_key( $_REQUEST['lang'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification
73 }
74
75 add_action( 'pre_comment_on_post', array( $this, 'pre_comment_on_post' ) ); // sets the language of comment
76 add_action( 'parse_query', array( $this, 'parse_main_query' ), 2 ); // sets the language in special cases
77 add_action( 'wp', array( $this, 'maybe_setcookie' ), 7 );
78 }
79
80 /**
81 * Sets the current language
82 * and fires the action 'pll_language_defined'.
83 *
84 * @since 1.2
85 *
86 * @param PLL_Language $curlang Current language.
87 * @return void
88 */
89 protected function set_language( $curlang ) {
90 // Don't set the language a second time
91 if ( isset( $this->curlang ) ) {
92 return;
93 }
94
95 // Final check in case $curlang has an unexpected value
96 // See https://wordpress.org/support/topic/detect-browser-language-sometimes-setting-null-language
97 $this->curlang = ( $curlang instanceof PLL_Language ) ? $curlang : $this->model->get_language( $this->options['default_lang'] );
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
104 /**
105 * Fires when the current language is defined.
106 *
107 * @since 0.9.5
108 *
109 * @param string $slug Current language code.
110 * @param PLL_Language $curlang Current language object.
111 */
112 do_action( 'pll_language_defined', $this->curlang->slug, $this->curlang );
113 }
114
115 /**
116 * Set a cookie to remember the language.
117 * Setting PLL_COOKIE to false will disable cookie although it will break some functionalities
118 *
119 * @since 1.5
120 *
121 * @return void
122 */
123 public function maybe_setcookie() {
124 // Don't set cookie in javascript when a cache plugin is active.
125 if ( ! pll_is_cache_active() && ! empty( $this->curlang ) && ! is_404() ) {
126 $args = array(
127 'domain' => 2 === $this->options['force_lang'] ? wp_parse_url( $this->links_model->home, PHP_URL_HOST ) : COOKIE_DOMAIN,
128 'samesite' => 3 === $this->options['force_lang'] ? 'None' : 'Lax',
129 );
130 PLL_Cookie::set( $this->curlang->slug, $args );
131 }
132 }
133
134 /**
135 * Get the preferred language according to the browser preferences.
136 *
137 * @since 1.8
138 *
139 * @return string|bool The preferred language slug or false.
140 */
141 public function get_preferred_browser_language() {
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'] ) ) );
144
145 $accept_langs->bubble_sort();
146
147 $languages = $this->model->get_languages_list( array( 'hide_empty' => true ) ); // Hides languages with no post.
148
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 );
157
158 return $accept_langs->find_best_match( $languages );
159 }
160
161 return false;
162 }
163
164 /**
165 * Returns the preferred language
166 * either from the cookie if it's a returning visit
167 * or according to browser preference
168 * or the default language
169 *
170 * @since 0.1
171 *
172 * @return object browser preferred language or default language
173 */
174 public function get_preferred_language() {
175 $language = false;
176 $cookie = false;
177
178 if ( isset( $_COOKIE[ PLL_COOKIE ] ) ) {
179 // Check first if the user was already browsing this site.
180 $language = sanitize_key( $_COOKIE[ PLL_COOKIE ] );
181 $cookie = true;
182 } elseif ( $this->options['browser'] ) {
183 $language = $this->get_preferred_browser_language();
184 }
185
186 /**
187 * Filter the visitor's preferred language (normally set first by cookie
188 * if this is not the first visit, then by the browser preferences).
189 * If no preferred language has been found or set by this filter,
190 * Polylang fallbacks to the default language
191 *
192 * @since 1.0
193 * @since 2.7 Added $cookie parameter.
194 *
195 * @param string|bool $language Preferred language code, false if none has been found.
196 * @param bool $cookie Whether the preferred language has been defined by the cookie.
197 */
198 $slug = apply_filters( 'pll_preferred_language', $language, $cookie );
199
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
201 return ( $lang = $this->model->get_language( $slug ) ) ? $lang : $this->model->get_language( $this->options['default_lang'] );
202 }
203
204 /**
205 * Sets the language when home page is requested
206 *
207 * @since 1.2
208 *
209 * @return void
210 */
211 protected function home_language() {
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
213 // Thanks to Ov3rfly http://wordpress.org/support/topic/enhance-feature-when-front-page-is-visited-set-language-according-to-browser
214 $language = $this->options['hide_default'] && ( wp_get_referer() || ! $this->options['browser'] ) ?
215 $this->model->get_language( $this->options['default_lang'] ) :
216 $this->get_preferred_language(); // Sets the language according to browser preference or default language
217 $this->set_language( $language );
218 }
219
220 /**
221 * To call when the home page has been requested
222 * Make sure to call this after 'setup_theme' has been fired as we need $wp_query
223 * Performs a redirection to the home page in the current language if needed
224 *
225 * @since 0.9
226 *
227 * @return void
228 */
229 public function home_requested() {
230 // We are already on the right page
231 if ( $this->options['default_lang'] == $this->curlang->slug && $this->options['hide_default'] ) {
232 $this->set_curlang_in_query( $GLOBALS['wp_query'] );
233
234 /**
235 * Fires when the site root page is requested
236 *
237 * @since 1.8
238 */
239 do_action( 'pll_home_requested' );
240 }
241 // Redirect to the home page in the right language
242 // Test to avoid crash if get_home_url returns something wrong
243 // FIXME why this happens? http://wordpress.org/support/topic/polylang-crashes-1
244 // Don't redirect if $_POST is not empty as it could break other plugins
245 elseif ( is_string( $redirect = $this->curlang->home_url ) && empty( $_POST ) ) { // phpcs:ignore WordPress.Security.NonceVerification
246 // Don't forget the query string which may be added by plugins
247 $query_string = wp_parse_url( pll_get_requested_url(), PHP_URL_QUERY );
248 if ( ! empty( $query_string ) ) {
249 $redirect .= ( $this->links_model->using_permalinks ? '?' : '&' ) . $query_string;
250 }
251
252 /**
253 * When a visitor reaches the site home, Polylang redirects to the home page in the correct language.
254 * This filter allows plugins to modify the redirected url or prevent this redirection
255 * /!\ this filter may be fired *before* the theme is loaded
256 *
257 * @since 1.1.1
258 *
259 * @param string $redirect the url the visitor will be redirected to
260 */
261 if ( $redirect = apply_filters( 'pll_redirect_home', $redirect ) ) {
262 $this->maybe_setcookie();
263 header( 'Vary: Accept-Language' );
264 wp_safe_redirect( $redirect, 302, POLYLANG );
265 exit;
266 }
267 }
268 }
269
270 /**
271 * Set the language when posting a comment
272 *
273 * @since 0.8.4
274 *
275 * @param int $post_id the post being commented
276 * @return void
277 */
278 public function pre_comment_on_post( $post_id ) {
279 $this->set_language( $this->model->post->get_language( $post_id ) );
280 }
281
282 /**
283 * Modifies some main query vars for the home page and the page for posts
284 * to enable one home page (and one page for posts) per language.
285 *
286 * @since 1.2
287 *
288 * @param WP_Query $query Instance of WP_Query.
289 * @return void
290 */
291 public function parse_main_query( $query ) {
292 if ( ! $query->is_main_query() ) {
293 return;
294 }
295
296 /**
297 * This filter allows to set the language based on information contained in the main query
298 *
299 * @since 1.8
300 *
301 * @param PLL_Language|false $lang Language object or false.
302 * @param WP_Query $query WP_Query object.
303 */
304 if ( $lang = apply_filters( 'pll_set_language_from_query', false, $query ) ) {
305 $this->set_language( $lang );
306 $this->set_curlang_in_query( $query );
307 }
308
309 // sets is_home on translated home page when it displays posts
310 // is_home must be true on page 2, 3... too
311 // as well as when searching an empty string: http://wordpress.org/support/topic/plugin-polylang-polylang-breaks-search-in-spun-theme
312 elseif ( ( count( $query->query ) == 1 || ( is_paged() && count( $query->query ) == 2 ) || ( isset( $query->query['s'] ) && ! $query->query['s'] ) ) && $lang = get_query_var( 'lang' ) ) {
313 $lang = $this->model->get_language( $lang );
314 $this->set_language( $lang ); // sets the language now otherwise it will be too late to filter sticky posts !
315 $query->is_home = true;
316 $query->is_archive = $query->is_tax = false;
317 }
318 }
319
320 /**
321 * Sets the current language in the query.
322 *
323 * @since 2.2
324 *
325 * @param WP_Query $query Instance of WP_Query.
326 * @return void
327 */
328 protected function set_curlang_in_query( &$query ) {
329 $pll_query = new PLL_Query( $query, $this->model );
330 $pll_query->set_language( $this->curlang );
331 }
332 }
333