PLL_Choose_Lang

Base class to choose the language.

Defined (1)

The class is defined in the following location(s).

/frontend/choose-lang.php  
  1. abstract class PLL_Choose_Lang { 
  2. public $links_model, $model, $options; 
  3. public $curlang; 
  4.  
  5. /** 
  6. * constructor 
  7. * @since 1.2 
  8. * @param object $polylang 
  9. */ 
  10. public function __construct( &$polylang ) { 
  11. $this->links_model = &$polylang->links_model; 
  12. $this->model = &$polylang->model; 
  13. $this->options = &$polylang->options; 
  14.  
  15. $this->curlang = &$polylang->curlang; 
  16.  
  17. /** 
  18. * sets the language for ajax requests 
  19. * and setup actions 
  20. * any child class must call this method if it overrides it 
  21. * @since 1.8 
  22. */ 
  23. public function init() { 
  24. if ( PLL_AJAX_ON_FRONT || false === stripos( $_SERVER['SCRIPT_FILENAME'], 'index.php' ) ) { 
  25. $this->set_language( empty( $_REQUEST['lang'] ) ? $this->get_preferred_language() : $this->model->get_language( $_REQUEST['lang'] ) ); 
  26.  
  27. add_action( 'pre_comment_on_post', array( $this, 'pre_comment_on_post' ) ); // sets the language of comment 
  28. add_action( 'parse_query', array( $this, 'parse_main_query' ), 2 ); // sets the language in special cases 
  29. add_action( 'wp', array( $this, 'maybe_setcookie' ), 7 ); 
  30.  
  31. /** 
  32. * writes language cookie 
  33. * loads user defined translations 
  34. * fires the action 'pll_language_defined' 
  35. * @since 1.2 
  36. * @param object $curlang current language 
  37. */ 
  38. protected function set_language( $curlang ) { 
  39. // don't set the language a second time 
  40. if ( isset( $this->curlang ) ) { 
  41. return; 
  42.  
  43. // final check in case $curlang has an unexpected value 
  44. // see https://wordpress.org/support/topic/detect-browser-language-sometimes-setting-null-language 
  45. $this->curlang = ( $curlang instanceof PLL_Language ) ? $curlang : $this->model->get_language( $this->options['default_lang'] ); 
  46.  
  47. $GLOBALS['text_direction'] = $this->curlang->is_rtl ? 'rtl' : 'ltr'; 
  48.  
  49. /** 
  50. * Fires when the current language is defined 
  51. * @since 0.9.5 
  52. * @param string $slug current language code 
  53. * @param object $curlang current language object 
  54. */ 
  55. do_action( 'pll_language_defined', $this->curlang->slug, $this->curlang ); 
  56.  
  57. /** 
  58. * set a cookie to remember the language. 
  59. * possibility to set PLL_COOKIE to false will disable cookie although it will break some functionalities 
  60. * @since 1.5 
  61. */ 
  62. public function maybe_setcookie() { 
  63. // check headers have not been sent to avoid ugly error 
  64. // cookie domain must be set to false for localhost ( default value for COOKIE_DOMAIN ) thanks to Stephen Harris. 
  65. if ( ! headers_sent() && PLL_COOKIE !== false && ! empty( $this->curlang ) && ( ! isset( $_COOKIE[ PLL_COOKIE ] ) || $_COOKIE[ PLL_COOKIE ] != $this->curlang->slug ) && ! is_404() ) { 
  66.  
  67. /** 
  68. * Filter the Polylang cookie duration 
  69. * @since 1.8 
  70. * @param int $duration cookie duration in seconds 
  71. */ 
  72. $expiration = apply_filters( 'pll_cookie_expiration', YEAR_IN_SECONDS ); 
  73.  
  74. setcookie( 
  75. PLL_COOKIE,  
  76. $this->curlang->slug,  
  77. time() + $expiration,  
  78. COOKIEPATH,  
  79. 2 == $this->options['force_lang'] ? parse_url( $this->links_model->home, PHP_URL_HOST ) : COOKIE_DOMAIN 
  80. ); 
  81.  
  82. /** 
  83. * get the preferred language according to the browser preferences 
  84. * code adapted from http://www.thefutureoftheweb.com/blog/use-accept-language-header 
  85. * @since 1.8 
  86. * @return string|bool the preferred language slug or false 
  87. */ 
  88. public function get_preferred_browser_language() { 
  89. $accept_langs = array(); 
  90.  
  91. if ( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) { 
  92. // break up string into pieces ( languages and q factors ) 
  93. 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 ); 
  94.  
  95. $k = $lang_parse[1]; 
  96. $v = $lang_parse[4]; 
  97.  
  98. if ( $n = count( $k ) ) { 
  99. // set default to 1 for any without q factor 
  100. foreach ( $v as $key => $val ) { 
  101. if ( '' === $val ) { 
  102. $v[ $key ] = 1; 
  103.  
  104. // bubble sort ( need a stable sort for Android, so can't use a PHP sort function ) 
  105. if ( $n > 1 ) { 
  106. for ( $i = 2; $i <= $n; $i++ ) { 
  107. for ( $j = 0; $j <= $n - 2; $j++ ) { 
  108. if ( $v[ $j ] < $v[ $j + 1 ] ) { 
  109. // swap values 
  110. $temp = $v[ $j ]; 
  111. $v[ $j ] = $v[ $j + 1 ]; 
  112. $v[ $j + 1 ] = $temp; 
  113. //swap keys 
  114. $temp = $k[ $j ]; 
  115. $k[ $j ] = $k[ $j + 1 ]; 
  116. $k[ $j + 1 ] = $temp; 
  117. $accept_langs = array_combine( $k, $v ); 
  118.  
  119. $languages = $this->model->get_languages_list( array( 'hide_empty' => true ) ); // hides languages with no post 
  120.  
  121. /** 
  122. * Filter the list of languages to use to match the browser preferences 
  123. * @since 1.9.3 
  124. * @param array $languages array of PLL_Language objects 
  125. */ 
  126. $languages = apply_filters( 'pll_languages_for_browser_preferences', $languages ); 
  127.  
  128. // looks through sorted list and use first one that matches our language list 
  129. foreach ( array_keys( $accept_langs ) as $accept_lang ) { 
  130. // first loop to match the exact locale 
  131. foreach ( $languages as $language ) { 
  132. if ( 0 === strcasecmp( $accept_lang, $language->get_locale( 'display' ) ) ) { 
  133. return $language->slug; 
  134.  
  135. // second loop to match the language set 
  136. foreach ( $languages as $language ) { 
  137. if ( 0 === stripos( $accept_lang, $language->slug ) || 0 === stripos( $language->get_locale( 'display' ), $accept_lang ) ) { 
  138. return $language->slug; 
  139. return false; 
  140.  
  141. /** 
  142. * returns the language according to browser preference or the default language 
  143. * @since 0.1 
  144. * @return object browser preferred language or default language 
  145. */ 
  146. public function get_preferred_language() { 
  147. // check first if the user was already browsing this site 
  148. if ( isset( $_COOKIE[ PLL_COOKIE ] ) ) { 
  149. return $this->model->get_language( $_COOKIE[ PLL_COOKIE ] ); 
  150.  
  151. /** 
  152. * Filter the visitor's preferred language (normally set first by cookie 
  153. * if this is not the first visit, then by the browser preferences). 
  154. * If no preferred language has been found or set by this filter,  
  155. * Polylang fallbacks to the default language 
  156. * @since 1.0 
  157. * @param string $language preferred language code 
  158. */ 
  159. $slug = apply_filters( 'pll_preferred_language', $this->options['browser'] ? $this->get_preferred_browser_language() : false ); 
  160.  
  161. // 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 
  162. return ( $lang = $this->model->get_language( $slug ) ) ? $lang : $this->model->get_language( $this->options['default_lang'] ); 
  163.  
  164. /** 
  165. * sets the language when home page is resquested 
  166. * @since 1.2 
  167. */ 
  168. protected function home_language() { 
  169. // test referer in case PLL_COOKIE is set to false 
  170. // thanks to Ov3rfly http://wordpress.org/support/topic/enhance-feature-when-front-page-is-visited-set-language-according-to-browser 
  171. $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'] ) ? 
  172. $this->model->get_language( $this->options['default_lang'] ) : 
  173. $this->get_preferred_language(); // sets the language according to browser preference or default language 
  174. $this->set_language( $language ); 
  175.  
  176. /** 
  177. * to call when the home page has been requested 
  178. * make sure to call this after 'setup_theme' has been fired as we need $wp_query 
  179. * performs a redirection to the home page in the current language if needed 
  180. * @since 0.9 
  181. */ 
  182. public function home_requested() { 
  183. // we are already on the right page 
  184. if ( $this->options['default_lang'] == $this->curlang->slug && $this->options['hide_default'] ) { 
  185. $this->set_lang_query_var( $GLOBALS['wp_query'], $this->curlang ); 
  186.  
  187. /** 
  188. * Fires when the site root page is requested 
  189. * @since 1.8 
  190. */ 
  191. do_action( 'pll_home_requested' ); 
  192. // redirect to the home page in the right language 
  193. // test to avoid crash if get_home_url returns something wrong 
  194. // FIXME why this happens? http://wordpress.org/support/topic/polylang-crashes-1 
  195. // don't redirect if $_POST is not empty as it could break other plugins 
  196. // don't forget the query string which may be added by plugins 
  197. elseif ( is_string( $redirect = $this->curlang->home_url ) && empty( $_POST ) ) { 
  198. $redirect = empty( $_SERVER['QUERY_STRING'] ) ? $redirect : $redirect . ( $this->links_model->using_permalinks ? '?' : '&' ) . $_SERVER['QUERY_STRING']; 
  199.  
  200. /** 
  201. * When a visitor reaches the site home, Polylang redirects to the home page in the correct language. 
  202. * This filter allows plugins to modify the redirected url or prevent this redirection 
  203. * @since 1.1.1 
  204. * @param string $redirect the url the visitor will be redirected to 
  205. */ 
  206. if ( $redirect = apply_filters( 'pll_redirect_home', $redirect ) ) { 
  207. wp_redirect( $redirect ); 
  208. exit; 
  209.  
  210. /** 
  211. * set the language when posting a comment 
  212. * @since 0.8.4 
  213. * @param int $post_id the post beeing commented 
  214. */ 
  215. public function pre_comment_on_post( $post_id ) { 
  216. $this->set_language( $this->model->post->get_language( $post_id ) ); 
  217.  
  218. /** 
  219. * modifies some main query vars for home page and page for posts 
  220. * to enable one home page ( and one page for posts ) per language 
  221. * @since 1.2 
  222. * @param object $query instance of WP_Query 
  223. */ 
  224. public function parse_main_query( $query ) { 
  225. if ( ! $query->is_main_query() ) { 
  226. return; 
  227.  
  228. /** 
  229. * This filter allows to set the language based on information contained in the main query 
  230. * @since 1.8 
  231. * @param bool|object $lang false or language object 
  232. * @param object $query WP_Query object 
  233. */ 
  234. if ( $lang = apply_filters( 'pll_set_language_from_query', false, $query ) ) { 
  235. $this->set_language( $lang ); 
  236. $this->set_lang_query_var( $query, $this->curlang ); 
  237.  
  238. // sets is_home on translated home page when it displays posts 
  239. // is_home must be true on page 2, 3... too 
  240. // as well as when searching an empty string: http://wordpress.org/support/topic/plugin-polylang-polylang-breaks-search-in-spun-theme 
  241. if ( 'posts' == get_option( 'show_on_front' ) && ( count( $query->query ) == 1 || ( is_paged() && count( $query->query ) == 2 ) || ( isset( $query->query['s'] ) && ! $query->query['s'] ) ) && $lang = get_query_var( 'lang' ) ) { 
  242. $lang = $this->model->get_language( $lang ); 
  243. $this->set_language( $lang ); // sets the language now otherwise it will be too late to filter sticky posts ! 
  244. $query->is_home = true; 
  245. $query->is_archive = $query->is_tax = false; 
  246.  
  247. /** 
  248. * sets the language in query 
  249. * optimized for ( needs ) WP 3.5+ 
  250. * @since 1.3 
  251. */ 
  252. public function set_lang_query_var( &$query, $lang ) { 
  253. // defining directly the tax_query ( rather than setting 'lang' avoids transforming the query by WP ) 
  254. $query->query_vars['tax_query'][] = array( 
  255. 'taxonomy' => 'language',  
  256. 'field' => 'term_taxonomy_id', // since WP 3.5 
  257. 'terms' => $lang->term_taxonomy_id,  
  258. 'operator' => 'IN',  
  259. );