PluginProbe
Polylang / 0.7
Polylang v0.7
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.7, at include/core.php

713 lines 28.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 $home;
12 private $options;
13 private $page_for_posts;
14 private $page_on_front;
15
16 function __construct() {
17
18 // init options often needed
19 $this->options = get_option('polylang');
20 $this->home = get_option('home');
21 $this->page_for_posts = get_option('page_for_posts');
22 $this->page_on_front = get_option('page_on_front');
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
29 // filters posts according to the language
30 add_filter('pre_get_posts', array(&$this, 'pre_get_posts'));
31 }
32
33 // set these filters and actions only once the current language has been defined
34 function add_language_filters() {
35 // filters the WordPress locale
36 add_filter('locale', array(&$this, 'get_locale'));
37
38 // filters categories and post tags by language
39 add_filter('terms_clauses', array(&$this, 'terms_clauses'), 10, 3);
40
41 // meta in the html head section
42 remove_action('wp_head', 'rel_canonical');
43 add_action('wp_head', array(&$this, 'wp_head'));
44
45 // prevents redirection of the homepage
46 add_filter('redirect_canonical', array(&$this, 'redirect_canonical'), 10, 2);
47
48 // adds javascript at the end of the document
49 add_action('wp_print_footer_scripts', array(&$this, 'wp_print_footer_scripts'));
50
51 // adds the language information in the search form
52 // 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
53 add_filter('get_search_form', array(&$this, 'get_search_form'), 99);
54
55 // filters the pages according to the current language in wp_list_pages
56 add_filter('wp_list_pages_excludes', array(&$this, 'wp_list_pages_excludes'));
57
58 // filters the comments according to the current language
59 add_filter('comments_clauses', array(&$this, 'comments_clauses'), 10, 2);
60
61 // rewrites archives, next and previous post links to filter them by language
62 foreach (array('getarchives', 'get_previous_post', 'get_next_post') as $filter)
63 foreach (array('_join', '_where') as $clause)
64 add_filter($filter.$clause, array(&$this, 'posts'.$clause));
65
66 // rewrites author and date links to filter them by language
67 foreach (array('feed_link', 'author_link', 'post_type_archive_link', 'year_link', 'month_link', 'day_link') as $filter)
68 add_filter($filter, array(&$this, 'archive_link'));
69
70 // optionally rewrite posts, pages links to filter them by language
71 if ($this->options['force_lang']) {
72 foreach (array('post_link', '_get_page_link', 'post_type_link') as $filter)
73 add_filter($filter, array(&$this, 'post_link'), 10, 2);
74 }
75
76 // rewrite post format (and optionally categories and post tags) archives links to filter them by language
77 add_filter('term_link', array(&$this, 'term_link'), 10, 3);
78
79 // filters the nav menus according to the current language
80 add_filter('wp_nav_menu_args', array(&$this, 'wp_nav_menu_args'));
81 add_filter('wp_nav_menu_items', array(&$this, 'wp_nav_menu_items'), 10, 2);
82 add_filter('wp_nav_menu_objects', array(&$this, 'wp_nav_menu_objects'), 10, 2);
83 add_filter('wp_page_menu', array(&$this, 'wp_page_menu'), 10, 2);
84
85 // filters the widgets according to the current language
86 add_filter('widget_display_callback', array(&$this, 'widget_display_callback'), 10, 3);
87
88 // strings translation (must be applied before WordPress applies its default formatting filters)
89 add_filter('widget_title', array(&$this, 'widget_title'), 1);
90 add_filter('bloginfo', array(&$this, 'bloginfo'), 1, 2);
91 add_filter('get_bloginfo_rss', array(&$this, 'bloginfo'), 1, 2);
92
93 // loads front page template on translated front page
94 add_filter('template_include', array(&$this, 'template_include'));
95
96 // modifies the home url
97 add_filter('home_url', array(&$this, 'home_url'));
98
99 // allows a new value for the 'show' parameter to display the homepage url according to the current language
100 // FIXME Backward compatibility for versions < 0.5 -> replaced by a filter on home_url
101 add_filter('bloginfo_url', array(&$this, 'bloginfo_url'), 10, 2);
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) ? $pref_lang : $this->get_language($this->options['default_lang']);
147 }
148
149 // returns the current language
150 function get_current_language() {
151
152 if($this->curlang)
153 return $this->curlang;
154
155 // no language set for 404 and attachment
156 if (is_404() || is_attachment())
157 return $this->get_preferred_language();
158
159 if ($var = get_query_var('lang'))
160 $lang = $this->get_language($var);
161
162 elseif ((is_single() || is_page()) && ( ($var = get_queried_object_id()) || ($var = get_query_var('p')) || ($var = get_query_var('page_id')) ))
163 $lang = $this->get_post_language($var);
164
165 else {
166 foreach (get_taxonomies(array('show_ui'=>true)) as $taxonomy) {
167 if ($var = get_query_var(get_taxonomy($taxonomy)->query_var))
168 $lang = $this->get_term_language($var, $taxonomy);
169 }
170 }
171 return (isset($lang)) ? $lang : false;
172 }
173
174 // save the default locale before we start any language manipulation
175 function init() {
176 $this->default_locale = get_locale();
177 }
178
179 // returns the locale based on current language
180 function get_locale($locale) {
181 return $this->curlang->description;
182 }
183
184 // saves all text domains in a table for later usage
185 function mofile($bool, $domain, $mofile) {
186 $this->list_textdomains[] = array ('mo' => $mofile, 'domain' => $domain);
187 return true; // prevents WP loading text domains as we will load them all later
188 }
189
190 // NOTE: I believe there are two ways for a plugin to force the WP language
191 // as done by xili_language and here: load text domains and reinitialize wp_locale with the action 'wp'
192 // as done by qtranslate: define the locale with the action 'plugins_loaded', but in this case, the language must be specified in the url.
193 function load_textdomains() {
194 // sets the current language
195 if (!($this->curlang = $this->get_current_language()))
196 return; // something went wrong
197
198 // set a cookie to remember the language and then set all our language filters and actions
199 setcookie('wordpress_polylang', $this->curlang->slug, time() + 31536000 /* 1 year */, COOKIEPATH, COOKIE_DOMAIN);
200 $this->add_language_filters();
201
202 // our override_load_textdomain filter has done its job. let's remove it before calling load_textdomain
203 remove_filter('override_load_textdomain', array(&$this, 'mofile'));
204
205 // now we can load text domains with the right language
206 $new_locale = get_locale();
207 foreach ($this->list_textdomains as $textdomain)
208 load_textdomain( $textdomain['domain'], str_replace($this->default_locale, $new_locale, $textdomain['mo']));
209
210 // and finally load user defined strings
211 global $l10n;
212 $mo = new MO();
213 $reader = new POMO_StringReader(base64_decode(get_option('polylang_mo'.$this->curlang->term_id)));
214 $mo->import_from_reader($reader);
215 $l10n['pll_string'] = &$mo;
216
217 // reinitializes wp_locale for weekdays and months, as well as for text direction
218 global $wp_locale;
219 $wp_locale->init();
220 $wp_locale->text_direction = get_metadata('term', $this->curlang->term_id, '_rtl', true) ? 'rtl' : 'ltr';
221 }
222
223 // filters posts according to the language
224 function pre_get_posts($query) {
225 $qvars = $query->query_vars;
226
227 // detect our exclude pages query and returns to avoid conflicts
228 // this test should be sufficient
229 if (isset($qvars['tax_query'][0]) && isset($qvars['tax_query'][0]['taxonomy']) && isset($qvars['tax_query'][0]['operator']))
230 return;
231
232 // homepage is requested, let's set the language
233 if (empty($query->query)) {
234 // find out the language
235 if ($this->options['hide_default'] && isset($_COOKIE['wordpress_polylang']))
236 $this->curlang = $this->get_language($this->options['default_lang']);
237 else
238 $this->curlang = $this->get_preferred_language(); // sets the language according to browser preference or default language
239
240 // we are already on the right page
241 if ($this->options['default_lang'] == $this->curlang->slug && $this->options['hide_default']) {
242 if ($this->page_on_front && $link_id = $this->get_post($this->page_on_front, $this->curlang))
243 $query->set('page_id', $link_id);
244 else
245 $query->set('lang', $this->curlang->slug);
246 }
247 // redirect to the home page in the right language
248 else {
249 if ($this->page_on_front && $link_id = $this->get_post($this->page_on_front, $this->curlang))
250 $url = _get_page_link($link_id);
251 else
252 $url = home_url('?lang='.$this->curlang->slug);
253
254 wp_redirect($url);
255 exit;
256 }
257 }
258
259 // sets is_home on translated home page when it displays posts
260 // is_home must be true on page 2, 3... too
261 if (!$this->page_on_front && $query->is_tax && (count($query->query) == 1 || (is_paged() && count($query->query) == 2))) {
262 $query->is_home = true;
263 $query->is_tax = false;
264 }
265
266 // sets the language for posts page in case the front page displays a static page
267 if ($this->page_for_posts) {
268 // If permalinks are used, WordPress does set and use $query->queried_object_id and sets $query->query_vars['page_id'] to 0
269 // and does set and use $query->query_vars['page_id'] if permalinks are not used :(
270 if (isset($query->queried_object_id))
271 $page_id = $query->queried_object_id;
272 elseif (isset($qvars['page_id']))
273 $page_id = $qvars['page_id'];
274
275 if (isset($page_id) && $page_id && $this->get_post($page_id, $this->get_post_language($this->page_for_posts)) == $this->page_for_posts) {
276 $query->set('lang',$this->get_post_language($page_id)->slug);
277 $query->queried_object_id = $this->page_for_posts;
278 $query->query_vars['page_id'] = $this->page_for_posts; // FIXME the trick works but breaks .current-menu-item and .current_page_item
279 $query->is_page = false;
280 $query->is_home = true;
281 $query->is_posts_page = true;
282 $query->is_singular = false;
283 }
284 }
285
286 // FIXME to generalize as I probably forget things
287 // sets the language in case we hide the default language
288 if ($this->options['hide_default'] && !isset($qvars['lang']) && (
289 (count($query->query) == 1 && isset($qvars['paged']) && $qvars['paged']) ||
290 (isset($qvars['m']) && $qvars['m']) ||
291 (count($query->query) == 1 && isset($qvars['feed']) && $qvars['feed']) ||
292 (isset($qvars['author']) && $qvars['author']) ||
293 (isset($qvars['post_type']) && $qvars['post_type'] && is_archive()) ))
294 $query->set('lang', $this->options['default_lang']);
295
296 // allow filtering recent posts by the current language
297 // take care not to break queries for non visible post types such as nav_menu_items, attachments...
298 if ($query->is_home && $this->curlang && (!isset($qvars['post_type']) || !in_array($qvars['post_type'], get_post_types(array('show_ui' => false)))))
299 $query->set('lang', $this->curlang->slug);
300
301 // remove pages query when the language is set unless we do a search
302 // FIXME is only search broken by this ?
303 if (isset($qvars['lang']) && $qvars['lang'] && !isset($qvars['post_type']) && !is_search())
304 $query->set('post_type', 'post');
305
306 // unset the is_archive flag for language pages to prevent loading the archive template
307 // keep archive flag for comment feed otherwise the language filter does not work
308 if (isset($qvars['lang']) && $qvars['lang'] && !is_comment_feed() &&
309 !is_post_type_archive() && !is_date() && !is_author() && !is_category() && !is_tag() && !is_tax('post_format'))
310 $query->is_archive = false;
311
312 // unset the is_tax flag for authors pages
313 // FIXME Probably I should do this for other cases
314 if (isset($qvars['lang']) && $qvars['lang'] && is_author())
315 $query->is_tax = false;
316
317 // sets a language for theme preview
318 if (isset($_GET['preview']))
319 $query->set('lang', $this->options['default_lang']);
320
321 if (PLL_DISPLAY_ALL) {
322 // add posts with no language set
323 $query->query_vars['tax_query'] = array(
324 'relation' => 'OR', array(
325 'taxonomy'=> 'language',
326 'terms'=> get_terms('language', array('fields'=>'ids')),
327 'operator'=>'NOT IN'));
328 }
329 }
330
331 // filters categories and post tags by language when needed
332 function terms_clauses($clauses, $taxonomies, $args) {
333 // does nothing except on taxonomies which have show_ui set to 1 (includes category and post_tags)
334 foreach ($taxonomies as $tax) {
335 if(!get_taxonomy($tax)->show_ui)
336 return $clauses;
337 }
338
339 // adds our clauses to filter by current language
340 return $this->_terms_clauses($clauses, $this->curlang, PLL_DISPLAY_ALL);
341 }
342
343 // meta in the html head section
344 function wp_head() {
345 // modifies the canonical link to the homepage
346 if (is_singular()) {
347 global $wp_the_query;
348 if ($id = $wp_the_query->get_queried_object_id()) {
349 if (is_page())
350 $link = _get_page_link($id); // ignores page_on_front unlike get_permalink
351 else
352 $link = get_permalink ($id);
353 echo "<link rel='canonical' href='$link' />\n";
354 }
355 }
356
357 // outputs references to translated pages (if exists) in the html head section
358 foreach ($this->get_languages_list() as $language) {
359 if ($language->slug != $this->curlang->slug && $url = $this->get_translation_url($language))
360 printf("<link hreflang='%s' href='%s' rel='alternate' />\n", esc_attr($language->slug), esc_url($url));
361 }
362 }
363
364 // prevents redirection of the homepage
365 function redirect_canonical($redirect_url, $requested_url) {
366 return $requested_url == _get_page_link($this->page_on_front) ? false : $redirect_url;
367 }
368
369 // adds some javascript workaround knowing it's not perfect...
370 function wp_print_footer_scripts() {
371 $js = '';
372
373 // modifies the search form since filtering get_search_form won't work if the template uses searchform.php
374 // don't use directly e[0] just in case there is somewhere else an element named 's'
375 // check before if the hidden input has not already been introduced by get_search_form
376 if (!$this->search_form_filter) {
377 $lang = esc_js($this->curlang->slug);
378 $js .= "e = document.getElementsByName('s');
379 for (i = 0; i < e.length; i++) {
380 if (e[i] == '[object HTMLInputElement]') {
381 var ih = document.createElement('input');
382 ih.type = 'hidden';
383 ih.name = 'lang';
384 ih.value = '$lang';
385 e[i].parentNode.appendChild(ih);
386 }
387 }";
388 }
389
390 if ($js)
391 echo "<script type='text/javascript'>" .$js. "</script>";
392 }
393
394 // adds the language information in the search form
395 // does not work if searchform.php is used
396 function get_search_form($form) {
397 if ($form) {
398 $this->search_form_filter = true;
399 $form = str_replace('</form>', '<input type="hidden" name="lang" value="'.esc_attr($this->curlang->slug).'" /></form>', $form);
400 }
401 return $form;
402 }
403
404 // excludes pages which are not in the current language for wp_list_pages
405 // useful for the pages widget
406 function wp_list_pages_excludes($pages) {
407 return array_merge($pages, $this->exclude_pages($this->curlang->term_id));
408 }
409
410 // filters the comments according to the current language mainly for the recent comments widget
411 function comments_clauses($clauses, $comment_query) {
412 // first test if wp_posts.ID already available in the query
413 if (strpos($clauses['join'], '.ID')) {
414 global $wpdb;
415 $clauses['join'] .= $wpdb->prepare(" INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = ID");
416 $clauses['where'] .= $wpdb->prepare(" AND pll_tr.term_taxonomy_id = %d", $this->curlang->term_taxonomy_id);
417 }
418 return $clauses;
419 }
420
421 // modifies the sql request for wp_get_archives an get_adjacent_post to filter by the current language
422 function posts_join($sql) {
423 global $wpdb;
424 return $sql . $wpdb->prepare(" INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = ID");
425 }
426
427 // modifies the sql request for wp_get_archives and get_adjacent_post to filter by the current language
428 function posts_where($sql) {
429 global $wpdb;
430 return $sql . $wpdb->prepare(" AND pll_tr.term_taxonomy_id = %d", $this->curlang->term_taxonomy_id);
431 }
432
433 // adds language information to a link when using pretty permalinks
434 function add_language_to_link($url, $lang) {
435 global $wp_rewrite;
436 if ($wp_rewrite->using_permalinks()) {
437 $base = $this->options['rewrite'] ? '/' : '/language/';
438 $slug = $this->options['default_lang'] == $lang->slug && $this->options['hide_default'] ? '' : $base.$lang->slug;
439 return esc_url(str_replace($this->home, $this->home.$slug, $url));
440 }
441 else
442 return add_query_arg( 'lang', $lang->slug, $url );
443 }
444
445 // modifies post & page links
446 function post_link($link, $post) {
447 $id = '_get_page_link' ==current_filter() ? $post : $post->ID;
448 return $this->add_language_to_link($link, $this->get_post_language($id));
449 }
450
451 // modifies term link
452 function term_link($link, $term, $tax) {
453 return $tax == 'post_format' || ($this->options['force_lang'] && $tax != 'language') ?
454 $this->add_language_to_link($link, $this->get_term_language($term->term_id)) : $link;
455 }
456
457 // modifies the author and date links to add the language parameter (as well as feed link)
458 function archive_link($link) {
459 return $this->add_language_to_link($link, $this->curlang);
460 }
461
462 // returns the url of the translation (if exists) of the current page
463 function get_translation_url($language) {
464 global $wp_query, $wp_rewrite;
465 $qvars = $wp_query->query;
466 $hide = $this->options['default_lang'] == $language->slug && $this->options['hide_default'];
467
468 // is_single is set to 1 for attachment but no language is set
469 if (is_single() && !is_attachment() && $id = $this->get_post($wp_query->queried_object_id, $language))
470 $url = get_permalink($id);
471
472 // page for posts
473 elseif (get_option('show_on_front') == 'page' && isset($wp_query->queried_object_id) && $wp_query->queried_object_id == $this->page_for_posts &&
474 $id = $this->get_post($this->page_for_posts, $language))
475 $url = get_permalink($id);
476
477 elseif (is_page() && $id = $this->get_post($wp_query->queried_object_id, $language))
478 $url = $hide && $id == $this->get_post($this->page_on_front, $language) ? $this->home : _get_page_link($id);
479
480 elseif (!is_tax('post_format') && !is_tax('language') && (is_category() || is_tag() || is_tax ()) ) {
481 $term = get_queried_object();
482 $lang = $this->get_term_language($term->term_id);
483 $taxonomy = $term->taxonomy;
484
485 if ($language->slug == $lang->slug)
486 $url = get_term_link($term, $taxonomy); // self link
487 elseif ($link_id = $this->get_translation('term', $term->term_id, $language))
488 $url = get_term_link(get_term($link_id, $taxonomy), $taxonomy);
489 }
490
491 // don't test if there are existing translations before creating the url as it would be very expensive in sql queries
492 elseif (is_archive()) {
493 if ($wp_rewrite->using_permalinks()) {
494 $base = $this->options['rewrite'] ? '/' : '/language/';
495 $base = $hide ? '' : $base.$language->slug;
496 $base = $this->home.$base.'/';
497
498 if (is_author())
499 $url = esc_url($base.'author/'.$qvars['author_name'].'/');
500
501 if (is_year())
502 $url = esc_url($base.$qvars['year'].'/');
503
504 if (is_month())
505 $url = esc_url($base.$qvars['year'].'/'.$qvars['monthnum'].'/');
506
507 if (is_day())
508 $url = esc_url($base.$qvars['year'].'/'.$qvars['monthnum'].'/'.$qvars['day'].'/');
509
510 if (is_tax('post_format'))
511 $url = esc_url($base.'type/'.$qvars['post_format'].'/');
512 }
513 else
514 $url = $hide ? remove_query_arg('lang') : add_query_arg('lang', $language->slug);
515 }
516
517 elseif (is_home() || is_tax('language') )
518 $url = $hide ? $this->home : get_term_link($language, 'language');
519
520 return isset($url) ? $url : null;
521 }
522
523 // filters the nav menus according to the current language
524 function wp_nav_menu_args($args) {
525 if (!$args['menu'] && $args['theme_location']) {
526 $menu_lang = get_option('polylang_nav_menus');
527 if (isset($menu_lang[$args['theme_location']][$this->curlang->slug]))
528 $args['menu'] = $menu_lang[$args['theme_location']][$this->curlang->slug];
529 }
530 return $args;
531 }
532
533 // filters the widgets according to the current language
534 function widget_display_callback($instance, $widget, $args) {
535 $widget_lang = get_option('polylang_widgets');
536 // don't display if a language filter is set and this is not the current one
537 return isset($widget_lang[$widget->id]) && $widget_lang[$widget->id] && $widget_lang[$widget->id] != $this->curlang->slug ? false : $instance;
538 }
539
540 // adds the language switcher at the end of the menu
541 function wp_nav_menu_items($items, $args) {
542 $menu_lang = get_option('polylang_nav_menus');
543 return isset($menu_lang[$args->theme_location]['switcher']) && $menu_lang[$args->theme_location]['switcher'] ?
544 $items . $this->the_languages(array_merge($menu_lang[$args->theme_location], array('menu' => 1, 'echo' => 0))) : $items;
545 }
546
547 // corrects some issues on front page and post pages nav menus items
548 function wp_nav_menu_objects($menu_items, $args) {
549 global $wp_query;
550
551 // corrects classes in the menu for posts page
552 // FIXME check for child pages
553 if ($wp_query->is_posts_page) {
554 $classes = array('current-menu-item', 'current_page_item', 'current_page_parent');
555 foreach($menu_items as $item) {
556 $item->classes = array_diff($item->classes, $classes);
557 if ($item->object_id == $this->get_post($this->page_for_posts, $this->curlang))
558 $item->classes = array_merge($item->classes, $classes);
559 }
560 }
561
562 foreach($menu_items as $item) {
563 if ($item->object == 'page')
564 $item->url = _get_page_link($item->object_id); // avoids bad link on translated front page
565 }
566
567 return $menu_items;
568 }
569
570 // corrects the output of the function for translated home
571 function wp_page_menu($menu, $args) {
572 global $wp_query;
573
574 // add current_page_item class to posts page
575 if ($wp_query->is_posts_page) {
576 $id = $this->get_post($this->page_for_posts, $this->curlang);
577 $menu = str_replace('<li class="page_item page-item-'.$id.'">', '<li class="page_item page-item-'.$id.' current_page_item">', $menu);
578 }
579
580 // add current_page_item class to home page
581 // normally only the homepage has no class. note the space in <li >
582 if ($this->is_front_page() && !is_paged())
583 $menu = str_replace('<li >', '<li class="current_page_item">', $menu);
584
585 // remove the 2nd occurrence of homepage (when translated)
586 if ($this->page_on_front) {
587 $id = $this->get_post($this->page_on_front, $this->curlang);
588 $url = _get_page_link($id);
589 $title = apply_filters( 'the_title', get_page($id)->post_title);
590 $menu = str_replace('<li class="page_item page-item-'.$id.'"><a href="'.$url.'">'.$title.'</a></li>', '', $menu);
591 $menu = str_replace('<li class="page_item page-item-'.$id.' current_page_item"><a href="'.$url.'">'.$title.'</a></li>', '', $menu);
592 }
593 return $menu;
594 }
595
596 // translates widget titles
597 function widget_title($title) {
598 return __($title, 'pll_string');
599 }
600
601 // translates site title and tagline
602 function bloginfo($output, $show) {
603 return in_array($show, array('', 'name', 'description')) ? __($output, 'pll_string') : $output;
604 }
605
606 // acts as is_front_page but knows about translated front page
607 function is_front_page() {
608 return ('posts' == get_option('show_on_front') && is_home()) ||
609 ('page' == get_option('show_on_front') && $this->page_on_front && is_page($this->get_post($this->page_on_front, $this->get_current_language()))) ||
610 (is_tax('language') && !is_archive());
611 }
612
613 // loads front page template on translated front page
614 function template_include($template) {
615 return ($this->is_front_page() && $front_page = get_front_page_template()) ? $front_page : $template;
616 }
617
618 // filters the home url to get the right language
619 function home_url($url) {
620 if ( !(did_action('template_redirect') && rtrim($url,'/') == rtrim($this->home,'/')) )
621 return $url;
622
623 // don't like this but at least for WP_Widget_Categories::widget, it seems to be the only solution
624 // FIXME are there other exceptions ?
625 foreach (debug_backtrace() as $trace) {
626 $exceptions = $trace['function'] == 'get_pagenum_link' ||
627 $trace['function'] == 'get_author_posts_url' ||
628 $trace['function'] == 'get_search_form' ||
629 (isset($trace['file']) && strpos($trace['file'], 'searchform.php')) ||
630 ($trace['function'] == 'widget' && $trace['class'] == 'WP_Widget_Categories');
631 if ($exceptions)
632 return $url;
633 }
634 return $this->get_home_url($this->curlang);
635 }
636
637 // returns the home url in the right language
638 function get_home_url($language) {
639 if ($this->options['default_lang'] == $language->slug && $this->options['hide_default'])
640 return trailingslashit($this->home);
641
642 // a static page is used as front page
643 if ($this->page_on_front && $id = $this->get_post($this->page_on_front, $language))
644 $url = _get_page_link($id);
645
646 return isset($url) ? $url : get_term_link($language, 'language');
647 }
648
649 // adds 'lang_url' as possible value to the 'show' parameter of bloginfo to display the home url in the correct language
650 // FIXME not tested
651 function bloginfo_url($output, $show) {
652 if ($show == 'lang_url') {
653 $url = $this->get_home_url($this->curlang);
654 $output = isset($url) ? $url : $this->home;
655 }
656 return $output;
657 }
658
659 // displays the language switcher
660 function the_languages($args = '') {
661 $defaults = array(
662 'dropdown' => 0, // display as list and not as dropdown
663 'echo' => 1, // echoes the list
664 'hide_if_empty' => 1, // hides languages with no posts (or pages)
665 'menu' => '0', // not for nav menu
666 'show_flags' => 0, // don't show flags
667 'show_names' => 1, // show language names
668 'force_home' => 0, // tries to find a translation (available only if display != dropdown)
669 'hide_if_no_translation' => 0, // don't hide the link if there is no translation
670 'hide_current' => 0, // don't hide current language
671 );
672 extract(wp_parse_args($args, $defaults));
673
674 if ($dropdown)
675 $output = $this->dropdown_languages(array('hide_empty' => $hide_if_empty, 'selected' => $this->curlang->slug));
676
677 else {
678 $output = '';
679
680 foreach ($this->get_languages_list($hide_if_empty) as $language) {
681 // hide current language
682 if ($this->curlang->term_id == $language->term_id && $hide_current)
683 continue;
684
685 $url = $force_home ? null : $this->get_translation_url($language);
686 $url = apply_filters('pll_the_language_link', $url, $language->slug, $language->description);
687
688 // hide if no translation exists
689 if (!isset($url) && $hide_if_no_translation)
690 continue;
691
692 $url = isset($url) ? $url : $this->get_home_url($language); // if the page is not translated, link to the home page
693
694 $class = 'lang-item lang-item-'.esc_attr($language->term_id);
695 $class .= $language->term_id == $this->curlang->term_id ? ' current-lang' : '';
696 $class .= $menu ? ' menu-item' : '';
697
698 $flag = $show_flags ? $this->get_flag($language) : '';
699 $name = $show_names || !$show_flags ? esc_html($language->name) : '';
700
701 $output .= sprintf("<li class='%s'><a hreflang='%s' href='%s'>%s</a></li>\n",
702 $class, esc_attr($language->slug), esc_url($url), $show_flags && $show_names ? $flag.'&nbsp;'.$name : $flag.$name);
703 }
704 }
705
706 if ($echo)
707 echo $output;
708 else
709 return $output;
710 }
711 }
712 ?>
713