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

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