PluginProbe
Polylang / 0.8.4
Polylang v0.8.4
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 / include / core.php

core.php in Polylang 0.8.4, at include/core.php

715 lines 29.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // filters posts and terms by language, rewrites links to include the language, etc...
3 // used only for frontend
4 class Polylang_Core extends Polylang_base {
5 private $curlang; // current language
6 private $default_locale;
7 private $list_textdomains = array(); // all text domains
8 private $search_form_filter = false; // did we pass our get_search_form filter ?
9
10 // options often needed
11 private $page_for_posts;
12 private $page_on_front;
13
14 function __construct() {
15 parent::__construct();
16
17 // init options often needed
18 $this->page_for_posts = get_option('page_for_posts');
19 $this->page_on_front = get_option('page_on_front');
20
21 // sets the language of comment
22 add_action('pre_comment_on_post', array(&$this, 'pre_comment_on_post'));
23
24 // text domain management
25 add_action('init', array(&$this, 'init'));
26 add_filter('override_load_textdomain', array(&$this, 'mofile'), 10, 3);
27 add_action('wp', array(&$this, 'load_textdomains'));
28 add_action('login_init', array(&$this, 'load_textdomains'));
29
30 // filters posts according to the language
31 add_filter('pre_get_posts', array(&$this, 'pre_get_posts'));
32
33 // filter sticky posts by current language
34 add_filter('option_sticky_posts', array(&$this, 'option_sticky_posts'));
35
36 // translates page for posts and page on front
37 add_filter('option_page_for_posts', array(&$this, 'translate_page'));
38 add_filter('option_page_on_front', array(&$this, 'translate_page'));
39 }
40
41 // set these filters and actions only once the current language has been defined
42 function add_language_filters() {
43 // filters the WordPress locale
44 add_filter('locale', array(&$this, 'get_locale'));
45
46 // modifies the language information in rss feed
47 // useful if WP < 3.4
48 add_filter('option_rss_language', array(&$this, 'option_rss_language'));
49
50 // filters categories and post tags by language
51 add_filter('terms_clauses', array(&$this, 'terms_clauses'), 10, 3);
52
53 // meta in the html head section
54 add_action('wp_head', array(&$this, 'wp_head'));
55
56 // modifies the page link in case the front page is not in the default language
57 add_filter('page_link', array(&$this, 'page_link'), 10, 2);
58
59 // prevents redirection of the homepage
60 add_filter('redirect_canonical', array(&$this, 'redirect_canonical'), 10, 2);
61
62 // adds javascript at the end of the document
63 add_action('wp_print_footer_scripts', array(&$this, 'wp_print_footer_scripts'));
64
65 // adds the language information in the search form
66 // low priority in case the search form is created using the same filter as described in http://codex.wordpress.org/Function_Reference/get_search_form
67 add_filter('get_search_form', array(&$this, 'get_search_form'), 99);
68
69 // filters the pages according to the current language in wp_list_pages
70 add_filter('wp_list_pages_excludes', array(&$this, 'wp_list_pages_excludes'));
71
72 // filters the comments according to the current language
73 add_filter('comments_clauses', array(&$this, 'comments_clauses'), 10, 2);
74
75 // rewrites archives, next and previous post links to filter them by language
76 foreach (array('getarchives', 'get_previous_post', 'get_next_post') as $filter)
77 foreach (array('_join', '_where') as $clause)
78 add_filter($filter.$clause, array(&$this, 'posts'.$clause));
79
80 // rewrites author and date links to filter them by language
81 foreach (array('feed_link', 'author_link', 'post_type_archive_link', 'year_link', 'month_link', 'day_link') as $filter)
82 add_filter($filter, array(&$this, 'archive_link'));
83
84 $this->add_post_term_link_filters(); // these filters are in base as they may be used on admin side too
85
86 // filters the nav menus according to the current language
87 add_filter('theme_mod_nav_menu_locations', array(&$this, 'nav_menu_locations'));
88 add_filter('wp_nav_menu_args', array(&$this, 'wp_nav_menu_args'));
89 add_filter('wp_nav_menu_items', array(&$this, 'wp_nav_menu_items'), 10, 2);
90
91 // filters the widgets according to the current language
92 add_filter('widget_display_callback', array(&$this, 'widget_display_callback'), 10, 3);
93
94 // strings translation (must be applied before WordPress applies its default formatting filters)
95 add_filter('widget_title', array(&$this, 'widget_title'), 1);
96 add_filter('bloginfo', array(&$this, 'bloginfo'), 1, 2);
97 add_filter('get_bloginfo_rss', array(&$this, 'bloginfo'), 1, 2);
98
99 // modifies the home url
100 if (PLL_FILTER_HOME_URL)
101 add_filter('home_url', array(&$this, 'home_url'));
102
103 // Template tag: displays the language switcher
104 // FIXME Backward compatibility for versions < 0.5 -> replaced by pll_the_languages
105 add_action('the_languages', array(&$this, 'the_languages'));
106 }
107
108 // returns the language according to browser preference or the default language
109 function get_preferred_language() {
110 // check first is the user was already browsing this site
111 if (isset($_COOKIE['wordpress_polylang']))
112 return $this->get_language($_COOKIE['wordpress_polylang']);
113
114 // sets the browsing language according to the browser preferences
115 // code adapted from http://www.thefutureoftheweb.com/blog/use-accept-language-header
116 if ($this->options['browser']) {
117 $accept_langs = array();
118
119 if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
120 // break up string into pieces (languages and q factors)
121 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);
122
123 if (count($lang_parse[1])) {
124 // NOTE: array_combine => PHP5
125 $accept_langs = array_combine($lang_parse[1], $lang_parse[4]); // create a list like "en" => 0.8
126 // set default to 1 for any without q factor
127 foreach ($accept_langs as $accept_lang => $val) {
128 if ($val === '') $accept_langs[$accept_lang] = 1;
129 }
130 arsort($accept_langs, SORT_NUMERIC); // sort list based on value
131 }
132 }
133
134 // looks through sorted list and use first one that matches our language list
135 $listlanguages = $this->get_languages_list(true); // hides languages with no post
136 foreach ($accept_langs as $accept_lang => $val) {
137 foreach ($listlanguages as $language) {
138 if (strpos($accept_lang, $language->slug) === 0 && !isset($pref_lang)) {
139 $pref_lang = $language;
140 }
141 }
142 }
143 } // options['browser']
144
145 // 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
146 return isset($pref_lang) && !is_wp_error($pref_lang) ? $pref_lang : $this->get_language($this->options['default_lang']);
147 }
148
149 // returns the current language
150 function get_current_language() {
151 if ($this->curlang)
152 return $this->curlang;
153
154 // no language set for 404 and attachment
155 if (is_404() || is_attachment() || current_filter() == 'login_init')
156 return $this->get_preferred_language();
157
158 if ($var = get_query_var('lang'))
159 $lang = $this->get_language($var);
160
161 elseif ((is_single() || is_page()) && ( ($var = get_queried_object_id()) || ($var = get_query_var('p')) || ($var = get_query_var('page_id')) ))
162 $lang = $this->get_post_language($var);
163
164 else {
165 foreach ($this->taxonomies as $taxonomy) {
166 if ($var = get_query_var(get_taxonomy($taxonomy)->query_var))
167 $lang = $this->get_term_language($var, $taxonomy);
168 }
169 }
170 return isset($lang) ? $lang : false;
171 }
172
173 // sets the language of comment
174 // useful to redirect to correct post comment url when adding the language to all url
175 function pre_comment_on_post($post_id) {
176 $this->curlang = $this->get_post_language($post_id);
177 $this->add_post_term_link_filters();
178 }
179
180 // save the default locale before we start any language manipulation
181 function init() {
182 $this->default_locale = get_locale();
183 }
184
185 // returns the locale based on current language
186 function get_locale($locale) {
187 return $this->curlang->description;
188 }
189
190 // modifies the language information in rss feed
191 function option_rss_language($value) {
192 return get_bloginfo_rss('language');
193 }
194
195 // saves all text domains in a table for later usage
196 function mofile($bool, $domain, $mofile) {
197 $this->list_textdomains[] = array ('mo' => $mofile, 'domain' => $domain);
198 return true; // prevents WP loading text domains as we will load them all later
199 }
200
201 // NOTE: I believe there are two ways for a plugin to force the WP language
202 // as done by xili_language and here: load text domains and reinitialize wp_locale with the action 'wp'
203 // as done by qtranslate: define the locale with the action 'plugins_loaded', but in this case, the language must be specified in the url.
204 function load_textdomains() {
205
206 // our override_load_textdomain filter has done its job. let's remove it before calling load_textdomain
207 remove_filter('override_load_textdomain', array(&$this, 'mofile'));
208
209 // check there is at least one language defined and sets the current language
210 if ($this->get_languages_list() && $this->curlang = $this->get_current_language()) {
211
212 // set a cookie to remember the language. check headers have not been sent to avoid ugly error
213 if (!headers_sent())
214 setcookie('wordpress_polylang', $this->curlang->slug, time() + 31536000 /* 1 year */, COOKIEPATH, COOKIE_DOMAIN);
215
216 // set all our language filters and actions
217 $this->add_language_filters();
218
219 // now we can load text domains with the right language
220 $new_locale = get_locale();
221 foreach ($this->list_textdomains as $textdomain)
222 load_textdomain( $textdomain['domain'], str_replace($this->default_locale, $new_locale, $textdomain['mo']));
223
224 // and finally load user defined strings
225 global $l10n;
226 $l10n['pll_string'] = $this->mo_import($this->curlang);
227
228 // reinitializes wp_locale for weekdays and months, as well as for text direction
229 global $wp_locale;
230 $wp_locale->init();
231 $wp_locale->text_direction = get_metadata('term', $this->curlang->term_id, '_rtl', true) ? 'rtl' : 'ltr';
232 }
233
234 else {
235 // cant't work so load the text domains with WordPress default language
236 foreach ($this->list_textdomains as $textdomain)
237 load_textdomain($textdomain['domain'], $textdomain['mo']);
238 }
239 }
240
241 // filters posts according to the language
242 function pre_get_posts($query) {
243 // don't make anything if no language has been defined yet
244 if (!$this->get_languages_list())
245 return;
246
247 $qvars = $query->query_vars;
248
249 // users may want to display content in a different language than the current one by setting it explicitely in the query
250 if ($this->curlang && isset($qvars['lang']) && $qvars['lang'])
251 return;
252
253 // detect our exclude pages query and returns to avoid conflicts
254 // this test should be sufficient
255 if (isset($qvars['tax_query'][0]['taxonomy']) && $qvars['tax_query'][0]['taxonomy'] == 'language' &&
256 isset($qvars['tax_query'][0]['operator']) && $qvars['tax_query'][0]['operator'] == 'NOT IN')
257 return;
258
259 // homepage is requested, let's set the language
260 if (is_home() && !$this->curlang) {
261 // special case for wp-signup.php & wp-activate.php for which WP set is_home to true
262 if (false === strpos($_SERVER['SCRIPT_NAME'], 'index.php')) {
263 $this->curlang = $this->get_preferred_language();
264 return;
265 }
266
267 // now, it should be the true homepage
268 // find out the language
269 if ($this->options['hide_default'] && isset($_COOKIE['wordpress_polylang']))
270 $this->curlang = $this->get_language($this->options['default_lang']);
271 else
272 $this->curlang = $this->get_preferred_language(); // sets the language according to browser preference or default language
273
274 // we are already on the right page
275 if ($this->options['default_lang'] == $this->curlang->slug && $this->options['hide_default']) {
276 if ($this->page_on_front && $link_id = $this->get_post($this->page_on_front, $this->curlang))
277 $query->set('page_id', $link_id);
278 else
279 $query->set('lang', $this->curlang->slug);
280 }
281 // redirect to the home page in the right language
282 else {
283 wp_redirect($this->get_home_url($this->curlang));
284 exit;
285 }
286 }
287
288 // redirect the language page to the homepage
289 if ($this->options['redirect_lang'] && is_tax('language') && count($query->query) == 1 && $this->page_on_front) {
290 $this->curlang = $this->get_language(get_query_var('lang'));
291 $query->parse_query('page_id='.$this->get_post($this->page_on_front, $this->curlang));
292 return;
293 }
294
295 // sets is_home on translated home page when it displays posts
296 // is_home must be true on page 2, 3... too
297 if (!$this->page_on_front && is_tax('language') && (count($query->query) == 1 || (is_paged() && count($query->query) == 2))) {
298 $query->is_home = true;
299 $query->is_tax = false;
300 $this->curlang = $this->get_language(get_query_var('lang')); // sets the language now otherwise it will be too late to filter sticky posts !
301 }
302
303 // sets the language for posts page in case the front page displays a static page
304 if ($this->page_for_posts) {
305 // If permalinks are used, WordPress does set and use $query->queried_object_id and sets $query->query_vars['page_id'] to 0
306 // and does set and use $query->query_vars['page_id'] if permalinks are not used :(
307 if (isset($qvars['pagename']) && $qvars['pagename'] && isset($query->queried_object_id))
308 $page_id = $query->queried_object_id;
309 elseif (isset($qvars['page_id']))
310 $page_id = $qvars['page_id'];
311
312 if (isset($page_id) && $page_id && $this->get_post($page_id, $this->get_post_language($this->page_for_posts)) == $this->page_for_posts) {
313 $this->page_for_posts = $page_id;
314 $this->curlang = $this->get_post_language($page_id);
315 $query->set('lang', $this->curlang->slug);
316 $query->is_page = false;
317 $query->is_home = true;
318 $query->is_posts_page = true;
319 $query->is_singular = false;
320 }
321 }
322
323 // FIXME to generalize as I probably forget things
324 $is_archive = (count($query->query) == 1 && isset($qvars['paged']) && $qvars['paged']) ||
325 (isset($qvars['m']) && $qvars['m']) ||
326 (isset($qvars['author']) && $qvars['author']) ||
327 (isset($qvars['post_type']) && is_post_type_archive() && in_array($qvars['post_type'], $this->post_types));
328
329 // sets 404 when the language is not set for archives needing the language in the url
330 if (!$this->options['hide_default'] && !isset($qvars['lang']) && !$GLOBALS['wp_rewrite']->using_permalinks() && $is_archive)
331 $query->set_404();
332
333 // sets the language in case we hide the default language
334 if ($this->options['hide_default'] && !isset($qvars['lang']) && ($is_archive || (count($query->query) == 1 && isset($qvars['feed']) && $qvars['feed']) ))
335 $query->set('lang', $this->options['default_lang']);
336
337 // allow filtering recent posts and secondary queries by the current language
338 // take care not to break queries for non visible post types such as nav_menu_items, attachments...
339 if (/*$query->is_home && */$this->curlang && (!isset($qvars['post_type']) || in_array($qvars['post_type'], $this->post_types) ||
340 (is_array($qvars['post_type']) && array_intersect($qvars['post_type'], $this->post_types)) ))
341 $query->set('lang', $this->curlang->slug);
342
343 // remove pages query when the language is set unless we do a search
344 // FIXME is only search broken by this ?
345 if (isset($qvars['lang']) && $qvars['lang'] && !isset($qvars['post_type']) && !is_search())
346 $query->set('post_type', 'post');
347
348 // unset the is_archive flag for language pages to prevent loading the archive template
349 // keep archive flag for comment feed otherwise the language filter does not work
350 if (isset($qvars['lang']) && $qvars['lang'] && !is_comment_feed() &&
351 !is_post_type_archive() && !is_date() && !is_author() && !is_category() && !is_tag() && !is_tax('post_format'))
352 $query->is_archive = false;
353
354 // unset the is_tax flag for authors pages and post types archives
355 // FIXME Probably I should do this for other cases
356 if (isset($qvars['lang']) && $qvars['lang'] && (is_author() || is_post_type_archive())) {
357 $query->is_tax = false;
358 unset($query->queried_object);
359 }
360
361 // sets a language for theme preview
362 if (isset($_GET['preview']))
363 $query->set('lang', $this->options['default_lang']);
364
365 if (PLL_DISPLAY_ALL) {
366 // add posts with no language set
367 $query->query_vars['tax_query'] = array(
368 'relation' => 'OR', array(
369 'taxonomy'=> 'language',
370 'terms'=> get_terms('language', array('fields'=>'ids')),
371 'operator'=>'NOT IN'));
372 }
373 }
374
375 // filter sticky posts by current language
376 function option_sticky_posts($posts) {
377 if ($this->curlang && !empty($posts)) {
378 foreach ($posts as $key=>$post_id) {
379 if ($this->get_post_language($post_id)->term_id != $this->curlang->term_id)
380 unset($posts[$key]);
381 }
382 }
383 return $posts;
384 }
385
386 // filters categories and post tags by language when needed
387 function terms_clauses($clauses, $taxonomies, $args) {
388 // does nothing except on taxonomies which are filterable
389 foreach ($taxonomies as $tax) {
390 if (!in_array($tax, $this->taxonomies))
391 return $clauses;
392 }
393
394 // adds our clauses to filter by current language
395 return $this->_terms_clauses($clauses, $this->curlang, PLL_DISPLAY_ALL);
396 }
397
398 // meta in the html head section
399 function wp_head() {
400 // outputs references to translated pages (if exists) in the html head section
401 foreach ($this->get_languages_list() as $language) {
402 if ($language->slug != $this->curlang->slug && $url = $this->get_translation_url($language))
403 printf("<link hreflang='%s' href='%s' rel='alternate' />\n", esc_attr($language->slug), esc_url($url));
404 }
405 }
406
407 // modifies the page link in case the front page is not in the default language
408 function page_link($link, $id) {
409 if ($this->options['redirect_lang'] && $this->page_on_front && $id == $this->get_post($this->page_on_front, $lang = $this->get_post_language($id)))
410 return $this->options['hide_default'] && $lang->slug == $this->options['default_lang'] ? trailingslashit($this->home) : get_term_link($lang, 'language');
411
412 if ($this->page_on_front && $this->options['hide_default'] && $id == $this->get_post($this->page_on_front, $this->options['default_lang']))
413 return trailingslashit($this->home);
414
415 return _get_page_link($id);
416 }
417
418 // prevents redirection of the homepage when using page on front
419 function redirect_canonical($redirect_url, $requested_url) {
420 return $requested_url == home_url('/') || $requested_url == $this->page_link('', get_option('page_on_front')) ? false : $redirect_url;
421 }
422
423 // adds some javascript workaround knowing it's not perfect...
424 function wp_print_footer_scripts() {
425 // modifies the search form since filtering get_search_form won't work if the template uses searchform.php or the search form is hardcoded
426 // don't use directly e[0] just in case there is somewhere else an element named 's'
427 // check before if the hidden input has not already been introduced by get_search_form
428 // thanks to AndyDeGroo for improving the code for compatility with old browsers
429 // http://wordpress.org/support/topic/development-of-polylang-version-08?replies=6#post-2645559
430 if (!$this->search_form_filter) {
431 $lang = esc_js($this->curlang->slug);
432 $js = "e = document.getElementsByName('s');
433 for (i = 0; i < e.length; i++) {
434 if (e[i].tagName.toUpperCase() == 'INPUT') {
435 var ih = document.createElement('input');
436 ih.type = 'hidden';
437 ih.name = 'lang';
438 ih.value = '$lang';
439 e[i].parentNode.appendChild(ih);
440 }
441 }";
442 echo "<script type='text/javascript'>" .$js. "</script>";
443 }
444 }
445
446 // adds the language information in the search form
447 // does not work if searchform.php is used or if the search form is hardcoded in another template file
448 function get_search_form($form) {
449 if ($form) {
450 $this->search_form_filter = true;
451 $form = str_replace('</form>', '<input type="hidden" name="lang" value="'.esc_attr($this->curlang->slug).'" /></form>', $form);
452 }
453 return $form;
454 }
455
456 // excludes pages which are not in the current language for wp_list_pages
457 // useful for the pages widget
458 function wp_list_pages_excludes($pages) {
459 return array_merge($pages, $this->exclude_pages($this->curlang->term_id));
460 }
461
462 // filters the comments according to the current language mainly for the recent comments widget
463 function comments_clauses($clauses, $comment_query) {
464 // first test if wp_posts.ID already available in the query
465 if (strpos($clauses['join'], '.ID')) {
466 global $wpdb;
467 $clauses['join'] .= $wpdb->prepare(" INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = ID");
468 $clauses['where'] .= $wpdb->prepare(" AND pll_tr.term_taxonomy_id = %d", $this->curlang->term_taxonomy_id);
469 }
470 return $clauses;
471 }
472
473 // modifies the sql request for wp_get_archives an get_adjacent_post to filter by the current language
474 function posts_join($sql) {
475 global $wpdb;
476 return $sql . $wpdb->prepare(" INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = ID");
477 }
478
479 // modifies the sql request for wp_get_archives and get_adjacent_post to filter by the current language
480 function posts_where($sql) {
481 global $wpdb;
482 return $sql . $wpdb->prepare(" AND pll_tr.term_taxonomy_id = %d", $this->curlang->term_taxonomy_id);
483 }
484
485 // modifies the author and date links to add the language parameter (as well as feed link)
486 function archive_link($link) {
487 return $this->add_language_to_link($link, $this->curlang);
488 }
489
490 // returns the url of the translation (if exists) of the current page
491 function get_translation_url($language) {
492 global $wp_query, $wp_rewrite;
493 $qvars = $wp_query->query;
494 $hide = $this->options['default_lang'] == $language->slug && $this->options['hide_default'];
495
496 // is_single is set to 1 for attachment but no language is set
497 if (is_single() && !is_attachment() && $id = $this->get_post($wp_query->queried_object_id, $language))
498 $url = get_permalink($id);
499
500 // page for posts
501 elseif (get_option('show_on_front') == 'page' && isset($wp_query->queried_object_id) && $wp_query->queried_object_id &&
502 $wp_query->queried_object_id == $this->page_for_posts && ($id = $this->get_post($this->page_for_posts, $language)))
503 $url = get_permalink($id);
504
505 elseif (is_page() && $id = $this->get_post($wp_query->queried_object_id, $language))
506 $url = $hide && $id == $this->get_post($this->page_on_front, $language) ? $this->home : get_page_link($id);
507
508 elseif (!is_tax('post_format') && !is_tax('language') && (is_category() || is_tag() || is_tax()) ) {
509 $term = get_queried_object();
510 $lang = $this->get_term_language($term->term_id);
511 $taxonomy = $term->taxonomy;
512
513 if ($language->slug == $lang->slug)
514 $url = get_term_link($term, $taxonomy); // self link
515 elseif ($link_id = $this->get_translation('term', $term->term_id, $language))
516 $url = get_term_link(get_term($link_id, $taxonomy), $taxonomy);
517 }
518
519 // don't test if there are existing translations before creating the url as it would be very expensive in sql queries
520 elseif (is_archive()) {
521 if ($wp_rewrite->using_permalinks()) {
522 $filters = array('author_link', 'post_type_archive_link', 'year_link', 'month_link', 'day_link');
523
524 // prevents filtering links by current language
525 remove_filter('term_link', array(&$this, 'term_link')); // for post format
526 foreach ($filters as $filter)
527 remove_filter($filter, array(&$this, 'archive_link'));
528
529 if (is_author())
530 $url = $this->add_language_to_link(get_author_posts_url(0, $qvars['author_name']), $language);
531
532 if (is_year())
533 $url = $this->add_language_to_link(get_year_link($qvars['year']), $language);
534
535 if (is_month())
536 $url = $this->add_language_to_link(get_month_link($qvars['year'], $qvars['monthnum']), $language);
537
538 if (is_day())
539 $url = $this->add_language_to_link(get_day_link($qvars['year'], $qvars['monthnum'], $qvars['day']), $language);
540
541 if (is_post_type_archive())
542 $url = $this->add_language_to_link(get_post_type_archive_link($qvars['post_type']), $language);
543
544 if (is_tax('post_format'))
545 $url = $this->add_language_to_link(get_post_format_link($qvars['post_format']), $language);
546
547 // put our language filters again
548 add_filter('term_link', array(&$this, 'term_link'), 10, 3);
549 foreach ($filters as $filter)
550 add_filter($filter, array(&$this, 'archive_link'));
551 }
552 else
553 $url = $hide ? remove_query_arg('lang') : add_query_arg('lang', $language->slug);
554 }
555
556 elseif (is_home() || is_tax('language') )
557 $url = $this->get_home_url($language);
558
559 return isset($url) ? $url : null;
560 }
561
562 // filters the nav menus according to the current language when called from get_nav_menu_locations()
563 // mainly for Artisteer generated themes
564 function nav_menu_locations($menus) {
565 if (is_array($menus)) {
566 foreach($menus as $location => $menu) {
567 $menu_lang = get_option('polylang_nav_menus');
568 if (isset($menu_lang[$location][$this->curlang->slug]))
569 $menus[$location] = $menu_lang[$location][$this->curlang->slug];
570 }
571 }
572 return $menus;
573 }
574
575 // filters the nav menus according to the current language when called from wp_nav_menus
576 function wp_nav_menu_args($args) {
577 if (!$args['menu'] && $args['theme_location']) {
578 $menu_lang = get_option('polylang_nav_menus');
579 if (isset($menu_lang[$args['theme_location']][$this->curlang->slug]))
580 $args['menu'] = $menu_lang[$args['theme_location']][$this->curlang->slug];
581 }
582 return $args;
583 }
584
585 // adds the language switcher at the end of the menu
586 function wp_nav_menu_items($items, $args) {
587 $menu_lang = get_option('polylang_nav_menus');
588 return isset($args->theme_location) && isset($menu_lang[$args->theme_location]['switcher']) && $menu_lang[$args->theme_location]['switcher'] ?
589 $items . $this->the_languages(array_merge($menu_lang[$args->theme_location], array('menu' => 1, 'echo' => 0))) : $items;
590 }
591
592 // filters the widgets according to the current language
593 function widget_display_callback($instance, $widget, $args) {
594 $widget_lang = get_option('polylang_widgets');
595 // don't display if a language filter is set and this is not the current one
596 return isset($widget_lang[$widget->id]) && $widget_lang[$widget->id] && $widget_lang[$widget->id] != $this->curlang->slug ? false : $instance;
597 }
598
599 // translates widget titles
600 function widget_title($title) {
601 return __($title, 'pll_string');
602 }
603
604 // translates site title and tagline
605 function bloginfo($output, $show) {
606 return in_array($show, array('', 'name', 'description')) ? __($output, 'pll_string') : $output;
607 }
608
609 // translates page for posts and page on front
610 function translate_page($value) {
611 return isset($this->curlang) && $value ? $this->get_post($value, $this->curlang) : $value;
612 }
613
614 // filters the home url to get the right language
615 function home_url($url) {
616 if (!did_action('template_redirect') || rtrim($url,'/') != $this->home)
617 return $url;
618
619 $theme = get_theme_root();
620 foreach (debug_backtrace() as $trace) {
621 $ok = $trace['function'] == 'wp_nav_menu' ||
622 // direct call from the theme
623 (isset($trace['file']) && !strpos($trace['file'], 'searchform.php') && strpos($trace['file'], $theme) !== false &&
624 in_array($trace['function'], array('home_url', 'bloginfo', 'get_bloginfo')) );
625
626 if ($ok)
627 return $this->get_home_url($this->curlang);
628 }
629
630 return $url;
631 }
632
633 // returns the home url in the right language
634 function get_home_url($language = '') {
635 if ($language == '')
636 $language = $this->curlang;
637
638 if ($this->options['default_lang'] == $language->slug && $this->options['hide_default'])
639 return trailingslashit($this->home);
640
641 // a static page is used as front page : /!\ don't use get_page_link to avoid infinite loop
642 if ($this->page_on_front && $id = $this->get_post($this->page_on_front, $language))
643 return $this->page_link('', $id);
644
645 return get_term_link($language, 'language');
646 }
647
648 // displays (or returns) the language switcher
649 function the_languages($args = '') {
650 $defaults = array(
651 'dropdown' => 0, // display as list and not as dropdown
652 'echo' => 1, // echoes the list
653 'hide_if_empty' => 1, // hides languages with no posts (or pages)
654 'menu' => '0', // not for nav menu
655 'show_flags' => 0, // don't show flags
656 'show_names' => 1, // show language names
657 'display_names_as' => 'name', // valid options are slug and name
658 'force_home' => 0, // tries to find a translation
659 'hide_if_no_translation' => 0, // don't hide the link if there is no translation
660 'hide_current' => 0, // don't hide current language
661 'post_id' => null, // if not null, link to translations of post defined by post_id
662 );
663 extract(wp_parse_args($args, $defaults));
664
665 if ($dropdown)
666 $output = $this->dropdown_languages(array('hide_empty' => $hide_if_empty, 'selected' => $this->curlang->slug));
667
668 else {
669 $output = '';
670
671 foreach ($this->get_languages_list($hide_if_empty) as $language) {
672 // hide current language
673 if ($this->curlang->term_id == $language->term_id && $hide_current)
674 continue;
675
676 $url = $post_id !== null && ($tr_id = $this->get_post($post_id, $language)) ? get_permalink($tr_id) :
677 $post_id === null && !$force_home ? $this->get_translation_url($language) : null;
678
679 $url = apply_filters('pll_the_language_link', $url, $language->slug, $language->description);
680
681 // hide if no translation exists
682 if (!isset($url) && $hide_if_no_translation)
683 continue;
684
685 $url = isset($url) ? $url : $this->get_home_url($language); // if the page is not translated, link to the home page
686
687 $class = 'lang-item lang-item-'.esc_attr($language->term_id);
688 $class .= $language->term_id == $this->curlang->term_id ? ' current-lang' : '';
689 $class .= $menu ? ' menu-item' : '';
690
691 $flag = $show_flags ? $this->get_flag($language) : '';
692 $name = $show_names || !$show_flags ? esc_html($display_names_as == 'slug' ? $language->slug : $language->name) : '';
693
694 $output .= sprintf("<li class='%s'><a hreflang='%s' href='%s'>%s</a></li>\n",
695 $class, esc_attr($language->slug), esc_url($url), $show_flags && $show_names ? $flag.'&nbsp;'.$name : $flag.$name);
696 }
697 }
698
699 $output = apply_filters('pll_the_languages', $output, $args);
700
701 if(!$echo)
702 return $output;
703 echo $output;
704 }
705
706 // just returns the current language for API
707 function current_language($args) {
708 return !isset($this->curlang) ? false :
709 $args == 'name' ? $this->curlang->name :
710 $args == 'locale' ? $this->curlang->description :
711 $this->curlang->slug;
712 }
713 }
714 ?>
715