| @@ -1,8 +1,5 @@ | ||
| 1 | 1 | <?php |
| 2 | -/** | |
| 3 | - * @package Polylang | |
| 4 | - */ | |
| 5 | 2 | |
| 6 | 3 | /** |
| 7 | 4 | * Base class to choose the language |
| 8 | 5 | * |
| @@ -34,10 +31,10 @@ | ||
| 34 | 31 | * |
| 35 | 32 | * @since 1.8 |
| 36 | 33 | */ |
| 37 | 34 | public function init() { |
| 38 | - if ( Polylang::is_ajax_on_front() || ! wp_using_themes() ) { | |
| 39 | - $this->set_language( empty( $_REQUEST['lang'] ) ? $this->get_preferred_language() : $this->model->get_language( sanitize_key( $_REQUEST['lang'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification | |
| 35 | + if ( Polylang::is_ajax_on_front() || false === stripos( $_SERVER['SCRIPT_FILENAME'], 'index.php' ) ) { | |
| 36 | + $this->set_language( empty( $_REQUEST['lang'] ) ? $this->get_preferred_language() : $this->model->get_language( $_REQUEST['lang'] ) ); | |
| 40 | 37 | } |
| 41 | 38 | |
| 42 | 39 | add_action( 'pre_comment_on_post', array( $this, 'pre_comment_on_post' ) ); // sets the language of comment |
| 43 | 40 | add_action( 'parse_query', array( $this, 'parse_main_query' ), 2 ); // sets the language in special cases |
| @@ -62,10 +59,9 @@ | ||
| 62 | 59 | // Final check in case $curlang has an unexpected value |
| 63 | 60 | // See https://wordpress.org/support/topic/detect-browser-language-sometimes-setting-null-language |
| 64 | 61 | $this->curlang = ( $curlang instanceof PLL_Language ) ? $curlang : $this->model->get_language( $this->options['default_lang'] ); |
| 65 | 62 | |
| 66 | - $GLOBALS['text_direction'] = $this->curlang->is_rtl ? 'rtl' : 'ltr'; | |
| 67 | - wp_styles()->text_direction = $GLOBALS['text_direction']; | |
| 63 | + $GLOBALS['text_direction'] = $this->curlang->is_rtl ? 'rtl' : 'ltr'; | |
| 68 | 64 | |
| 69 | 65 | /** |
| 70 | 66 | * Fires when the current language is defined |
| 71 | 67 | * |
| @@ -83,15 +79,31 @@ | ||
| 83 | 79 | * |
| 84 | 80 | * @since 1.5 |
| 85 | 81 | */ |
| 86 | 82 | public function maybe_setcookie() { |
| 87 | - // Don't set cookie in javascript when a cache plugin is active. | |
| 88 | - if ( ! pll_is_cache_active() && ! empty( $this->curlang ) && ! is_404() ) { | |
| 89 | - $args = array( | |
| 90 | - 'domain' => 2 === $this->options['force_lang'] ? wp_parse_url( $this->links_model->home, PHP_URL_HOST ) : COOKIE_DOMAIN, | |
| 91 | - 'samesite' => 3 === $this->options['force_lang'] ? 'None' : 'Lax', | |
| 83 | + // Don't set cookie in javascript when a cache plugin is active | |
| 84 | + // Check headers have not been sent to avoid ugly error | |
| 85 | + // Cookie domain must be set to false for localhost ( default value for COOKIE_DOMAIN ) thanks to Stephen Harris. | |
| 86 | + if ( ! pll_is_cache_active() && ! headers_sent() && PLL_COOKIE !== false && ! empty( $this->curlang ) && ( ! isset( $_COOKIE[ PLL_COOKIE ] ) || $_COOKIE[ PLL_COOKIE ] != $this->curlang->slug ) && ! is_404() ) { | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * Filter the Polylang cookie duration | |
| 90 | + * /!\ this filter may be fired *before* the theme is loaded | |
| 91 | + * | |
| 92 | + * @since 1.8 | |
| 93 | + * | |
| 94 | + * @param int $duration cookie duration in seconds | |
| 95 | + */ | |
| 96 | + $expiration = apply_filters( 'pll_cookie_expiration', YEAR_IN_SECONDS ); | |
| 97 | + | |
| 98 | + setcookie( | |
| 99 | + PLL_COOKIE, | |
| 100 | + $this->curlang->slug, | |
| 101 | + time() + $expiration, | |
| 102 | + COOKIEPATH, | |
| 103 | + 2 == $this->options['force_lang'] ? parse_url( $this->links_model->home, PHP_URL_HOST ) : COOKIE_DOMAIN, | |
| 104 | + is_ssl() | |
| 92 | 105 | ); |
| 93 | - PLL_Cookie::set( $this->curlang->slug, $args ); | |
| 94 | 106 | } |
| 95 | 107 | } |
| 96 | 108 | |
| 97 | 109 | /** |
| @@ -106,13 +118,9 @@ | ||
| 106 | 118 | $accept_langs = array(); |
| 107 | 119 | |
| 108 | 120 | if ( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) { |
| 109 | 121 | // 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 | - ); | |
| 122 | + preg_match_all( '/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*((?>1|0)(?>\.[0-9]+)?))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse ); | |
| 115 | 123 | |
| 116 | 124 | $k = $lang_parse[1]; |
| 117 | 125 | $v = $lang_parse[4]; |
| 118 | 126 | |
| @@ -144,9 +152,9 @@ | ||
| 144 | 152 | $accept_langs = array_combine( $k, $v ); |
| 145 | 153 | } |
| 146 | 154 | } |
| 147 | 155 | |
| 148 | - $accept_langs = array_filter( $accept_langs ); // Remove languages marked as unacceptable (q=0). | |
| 156 | + $accept_langs = wp_list_filter( $accept_langs, array( '0' ), 'NOT' ); // Remove languages markes as unacceptable (q=0). | |
| 149 | 157 | |
| 150 | 158 | $languages = $this->model->get_languages_list( array( 'hide_empty' => true ) ); // Hides languages with no post |
| 151 | 159 | |
| 152 | 160 | /** |
| @@ -177,12 +185,9 @@ | ||
| 177 | 185 | return false; |
| 178 | 186 | } |
| 179 | 187 | |
| 180 | 188 | /** |
| 181 | - * Returns the preferred language | |
| 182 | - * either from the cookie if it's a returning visit | |
| 183 | - * or according to browser preference | |
| 184 | - * or the default language | |
| 189 | + * Returns the language according to browser preference or the default language | |
| 185 | 190 | * |
| 186 | 191 | * @since 0.1 |
| 187 | 192 | * |
| 188 | 193 | * @return object browser preferred language or default language |
| @@ -187,17 +192,11 @@ | ||
| 187 | 192 | * |
| 188 | 193 | * @return object browser preferred language or default language |
| 189 | 194 | */ |
| 190 | 195 | public function get_preferred_language() { |
| 191 | - $language = false; | |
| 192 | - $cookie = false; | |
| 193 | - | |
| 196 | + // check first if the user was already browsing this site | |
| 194 | 197 | if ( isset( $_COOKIE[ PLL_COOKIE ] ) ) { |
| 195 | - // Check first if the user was already browsing this site. | |
| 196 | - $language = sanitize_key( $_COOKIE[ PLL_COOKIE ] ); | |
| 197 | - $cookie = true; | |
| 198 | - } elseif ( $this->options['browser'] ) { | |
| 199 | - $language = $this->get_preferred_browser_language(); | |
| 198 | + return $this->model->get_language( $_COOKIE[ PLL_COOKIE ] ); | |
| 200 | 199 | } |
| 201 | 200 | |
| 202 | 201 | /** |
| 203 | 202 | * Filter the visitor's preferred language (normally set first by cookie |
| @@ -205,16 +204,14 @@ | ||
| 205 | 204 | * If no preferred language has been found or set by this filter, |
| 206 | 205 | * Polylang fallbacks to the default language |
| 207 | 206 | * |
| 208 | 207 | * @since 1.0 |
| 209 | - * @since 2.7 Added $cookie parameter. | |
| 210 | 208 | * |
| 211 | - * @param string|bool $language Preferred language code, false if none has been found. | |
| 212 | - * @param bool $cookie Whether the preferred language has been defined by the cookie. | |
| 209 | + * @param string $language preferred language code | |
| 213 | 210 | */ |
| 214 | - $slug = apply_filters( 'pll_preferred_language', $language, $cookie ); | |
| 211 | + $slug = apply_filters( 'pll_preferred_language', $this->options['browser'] ? $this->get_preferred_browser_language() : false ); | |
| 215 | 212 | |
| 216 | - // 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 | |
| 213 | + // 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 | 214 | return ( $lang = $this->model->get_language( $slug ) ) ? $lang : $this->model->get_language( $this->options['default_lang'] ); |
| 218 | 215 | } |
| 219 | 216 | |
| 220 | 217 | /** |
| @@ -222,13 +219,13 @@ | ||
| 222 | 219 | * |
| 223 | 220 | * @since 1.2 |
| 224 | 221 | */ |
| 225 | 222 | protected function home_language() { |
| 226 | - // 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 | - // Thanks to Ov3rfly http://wordpress.org/support/topic/enhance-feature-when-front-page-is-visited-set-language-according-to-browser | |
| 228 | - $language = $this->options['hide_default'] && ( wp_get_referer() || ! $this->options['browser'] ) ? | |
| 223 | + // test referer in case PLL_COOKIE is set to false | |
| 224 | + // thanks to Ov3rfly http://wordpress.org/support/topic/enhance-feature-when-front-page-is-visited-set-language-according-to-browser | |
| 225 | + $language = $this->options['hide_default'] && ( ( isset( $_SERVER['HTTP_REFERER'] ) && in_array( parse_url( $_SERVER['HTTP_REFERER'], PHP_URL_HOST ), $this->links_model->get_hosts() ) ) || ! $this->options['browser'] ) ? | |
| 229 | 226 | $this->model->get_language( $this->options['default_lang'] ) : |
| 230 | - $this->get_preferred_language(); // Sets the language according to browser preference or default language | |
| 227 | + $this->get_preferred_language(); // sets the language according to browser preference or default language | |
| 231 | 228 | $this->set_language( $language ); |
| 232 | 229 | } |
| 233 | 230 | |
| 234 | 231 | /** |
| @@ -253,14 +250,11 @@ | ||
| 253 | 250 | // Redirect to the home page in the right language |
| 254 | 251 | // Test to avoid crash if get_home_url returns something wrong |
| 255 | 252 | // FIXME why this happens? http://wordpress.org/support/topic/polylang-crashes-1 |
| 256 | 253 | // 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 | |
| 258 | - // Don't forget the query string which may be added by plugins | |
| 259 | - $query_string = wp_parse_url( pll_get_requested_url(), PHP_URL_QUERY ); | |
| 260 | - if ( ! empty( $query_string ) ) { | |
| 261 | - $redirect .= ( $this->links_model->using_permalinks ? '?' : '&' ) . $query_string; | |
| 262 | - } | |
| 254 | + // Don't forget the query string which may be added by plugins | |
| 255 | + elseif ( is_string( $redirect = $this->curlang->home_url ) && empty( $_POST ) ) { | |
| 256 | + $redirect = empty( $_SERVER['QUERY_STRING'] ) ? $redirect : $redirect . ( $this->links_model->using_permalinks ? '?' : '&' ) . $_SERVER['QUERY_STRING']; | |
| 263 | 257 | |
| 264 | 258 | /** |
| 265 | 259 | * When a visitor reaches the site home, Polylang redirects to the home page in the correct language. |
| 266 | 260 | * This filter allows plugins to modify the redirected url or prevent this redirection |
| @@ -271,10 +265,9 @@ | ||
| 271 | 265 | * @param string $redirect the url the visitor will be redirected to |
| 272 | 266 | */ |
| 273 | 267 | if ( $redirect = apply_filters( 'pll_redirect_home', $redirect ) ) { |
| 274 | 268 | $this->maybe_setcookie(); |
| 275 | - header( 'Vary: Accept-Language' ); | |
| 276 | - wp_safe_redirect( $redirect, 302, POLYLANG ); | |
| 269 | + wp_redirect( $redirect, 302, POLYLANG ); | |
| 277 | 270 | exit; |
| 278 | 271 | } |
| 279 | 272 | } |
| 280 | 273 | } |