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

709 lines 28.0 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 feed links to filter them by language
62 add_filter('feed_link', array(&$this, 'feed_link'), 10, 2);
63
64 // rewrites archives links to filter them by language
65 add_filter('getarchives_join', array(&$this, 'posts_join'));
66 add_filter('getarchives_where', array(&$this, 'posts_where'));
67
68 // rewrites author and date links to filter them by language
69 add_filter('author_link', array(&$this, 'archive_link'));
70 add_filter('year_link', array(&$this, 'archive_link'));
71 add_filter('month_link', array(&$this, 'archive_link'));
72 add_filter('day_link', array(&$this, 'archive_link'));
73
74 // rewrites next and previous post links to filter them by language
75 add_filter('get_previous_post_join', array(&$this, 'posts_join'));
76 add_filter('get_next_post_join', array(&$this, 'posts_join'));
77 add_filter('get_previous_post_where', array(&$this, 'posts_where'));
78 add_filter('get_next_post_where', array(&$this, 'posts_where'));
79
80 // filters the nav menus according to the current language
81 add_filter('wp_nav_menu_args', array(&$this, 'wp_nav_menu_args'));
82 add_filter('wp_nav_menu_items', array(&$this, 'wp_nav_menu_items'), 10, 2);
83 add_filter('wp_nav_menu_objects', array(&$this, 'wp_nav_menu_objects'), 10, 2);
84 add_filter('wp_page_menu', array(&$this, 'wp_page_menu'), 10, 2);
85
86 // filters the widgets according to the current language
87 add_filter('widget_display_callback', array(&$this, 'widget_display_callback'), 10, 3);
88
89 // strings translation (must be applied before WordPress applies its default formatting filters)
90 add_filter('widget_title', array(&$this, 'widget_title'), 1);
91 add_filter('bloginfo', 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 compatibily 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 compatibily 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 if($this->curlang)
152 return $this->curlang;
153
154 // no language set for 404 and attachment
155 if (is_404() || is_attachment())
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())
162 $lang = $this->get_post_language($var);
163
164 else {
165 foreach (get_taxonomies(array('show_ui'=>true)) as $taxonomy) {
166 if ($var = get_query_var(get_taxonomy($taxonomy)->query_var))
167 $lang = $this->get_term_language($var, $taxonomy);
168 }
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
218 global $wp_locale;
219 $wp_locale->init();
220 }
221
222 // filters posts according to the language
223 function pre_get_posts($query) {
224 global $wp_rewrite;
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 if (!$this->page_on_front && $query->is_tax && count($query->query) == 1) {
261 $query->is_home = true;
262 $query->is_tax = false;
263 }
264
265 // sets the language for posts page in case the front page displays a static page
266 if ($this->page_for_posts) {
267 // If permalinks are used, WordPress does set and use $query->queried_object_id and sets $query->query_vars['page_id'] to 0
268 // and does set and use $query->query_vars['page_id'] if permalinks are not used :(
269 if (isset($query->queried_object_id))
270 $page_id = $query->queried_object_id;
271 elseif (isset($qvars['page_id']))
272 $page_id = $qvars['page_id'];
273
274 if (isset($page_id) && $page_id && $this->get_post($page_id, $this->get_post_language($this->page_for_posts)) == $this->page_for_posts) {
275 $query->set('lang',$this->get_post_language($page_id)->slug);
276 $query->queried_object_id = $this->page_for_posts;
277 $query->query_vars['page_id'] = $this->page_for_posts; // FIXME the trick works but breaks .current-menu-item and .current_page_item
278 $query->is_page = false;
279 $query->is_home = true;
280 $query->is_posts_page = true;
281 $query->is_singular = false;
282 }
283 }
284
285 // FIXME to generalize as I probably forget things
286 // sets the language in case we hide the default language
287 if ($this->options['hide_default'] && !isset($qvars['lang']) && (
288 (count($query->query) == 1 && isset($qvars['paged']) && $qvars['paged']) ||
289 isset($qvars['m']) && $qvars['m'] ||
290 isset($qvars['feed']) && $qvars['feed'] ||
291 isset($qvars['author']) && $qvars['author']))
292 $query->set('lang', $this->options['default_lang']);
293
294 // allow filtering recent posts by the current language
295 // take care not to break queries for non visible post types such as nav_menu_items, attachments...
296 if ($query->is_home && $this->curlang && (!isset($qvars['post_type']) || !in_array($qvars['post_type'], get_post_types(array('show_ui' => false)))))
297 $query->set('lang', $this->curlang->slug);
298
299 // remove pages query when the language is set unless we do a search
300 // FIXME is only search broken by this ?
301 if (isset($qvars['lang']) && $qvars['lang'] && !isset($qvars['post_type']) && !is_search())
302 $query->set('post_type', 'post');
303
304 // unset the is_archive flag for language pages to prevent loading the archive template
305 // keep archive flag for comment feed otherwise the language filter does not work
306 if (isset($qvars['lang']) && $qvars['lang'] && !is_post_type_archive() && !is_date() && !is_author() && !is_category() && !is_tag() && !is_comment_feed())
307 $query->is_archive = false;
308
309 // unset the is_tax flag for authors pages
310 // FIXME Probably I should do this for other cases
311 if (isset($qvars['lang']) && $qvars['lang'] && is_author())
312 $query->is_tax = false;
313
314 // sets a language for theme preview
315 if (isset($_GET['preview']))
316 $query->set('lang', $this->options['default_lang']);
317
318 if (PLL_DISPLAY_ALL) {
319 // add posts with no language set
320 $query->query_vars['tax_query'] = array(
321 'relation' => 'OR', array(
322 'taxonomy'=> 'language',
323 'terms'=> get_terms('language', array('fields'=>'ids')),
324 'operator'=>'NOT IN'));
325 }
326 }
327
328 // filters categories and post tags by language when needed
329 function terms_clauses($clauses, $taxonomies, $args) {
330 // does nothing except on taxonomies which have show_ui set to 1 (includes category and post_tags)
331 foreach ($taxonomies as $tax) {
332 if(!get_taxonomy($tax)->show_ui)
333 return $clauses;
334 }
335
336 // adds our clauses to filter by current language
337 return $this->_terms_clauses($clauses, $this->curlang, PLL_DISPLAY_ALL);
338 }
339
340 // meta in the html head section
341 function wp_head() {
342 // modifies the canonical link to the homepage
343 if (is_singular()) {
344 global $wp_the_query;
345 if ($id = $wp_the_query->get_queried_object_id()) {
346 if (is_page())
347 $link = _get_page_link($id); // ignores page_on_front unlike get_permalink
348 else
349 $link = get_permalink ($id);
350 echo "<link rel='canonical' href='$link' />\n";
351 }
352 }
353
354 // outputs references to translated pages (if exists) in the html head section
355 foreach ($this->get_languages_list() as $language) {
356 if ($language->slug != $this->curlang->slug && $url = $this->get_translation_url($language))
357 printf("<link hreflang='%s' href='%s' rel='alternate' />\n", esc_attr($language->slug), esc_url($url));
358 }
359 }
360
361 // prevents redirection of the homepage
362 function redirect_canonical($redirect_url, $requested_url) {
363 return $requested_url == _get_page_link($this->page_on_front) ? false : $redirect_url;
364 }
365
366 // adds some javascript workaround knowing it's not perfect...
367 function wp_print_footer_scripts() {
368 $js = '';
369
370 // modifies the search form since filtering get_search_form won't work if the template uses searchform.php
371 // don't use directly e[0] just in case there is somewhere else an element named 's'
372 // check before if the hidden input has not already been introduced by get_search_form
373 if (!$this->search_form_filter) {
374 $lang = esc_js($this->curlang->slug);
375 $js .= "e = document.getElementsByName('s');
376 for (i = 0; i < e.length; i++) {
377 if (e[i] == '[object HTMLInputElement]') {
378 var ih = document.createElement('input');
379 ih.type = 'hidden';
380 ih.name = 'lang';
381 ih.value = '$lang';
382 e[i].parentNode.appendChild(ih);
383 }
384 }";
385 }
386
387 if ($js)
388 echo "<script type='text/javascript'>" .$js. "</script>";
389 }
390
391 // adds the language information in the search form
392 // does not work if searchform.php is used
393 function get_search_form($form) {
394 if ($form) {
395 $this->search_form_filter = true;
396 $form = str_replace('</form>', '<input type="hidden" name="lang" value="'.esc_attr($this->curlang->slug).'" /></form>', $form);
397 }
398 return $form;
399 }
400
401 // excludes pages which are not in the current language for wp_list_pages
402 // useful for the pages widget
403 function wp_list_pages_excludes($pages) {
404 return array_merge($pages, $this->exclude_pages($this->curlang->term_id));
405 }
406
407 // filters the comments according to the current language mainly for the recent comments widget
408 function comments_clauses($clauses, $comment_query) {
409 // first test if wp_posts.ID already available in the query
410 if (strpos($clauses['join'], '.ID')) {
411 global $wpdb;
412 $clauses['join'] .= $wpdb->prepare(" INNER JOIN $wpdb->term_relationships AS tr ON tr.object_id = ID");
413 $clauses['where'] .= $wpdb->prepare(" AND tr.term_taxonomy_id = %d", $this->curlang->term_taxonomy_id);
414 }
415 return $clauses;
416 }
417
418 // adds language information to a link when using pretty permalinks
419 function add_language_to_link($url) {
420 $base = $this->options['rewrite'] ? '/' : '/language/';
421 $slug = $this->options['default_lang'] == $this->curlang->slug && $this->options['hide_default'] ? '' : $base.$this->curlang->slug;
422 return esc_url(str_replace($this->home, $this->home.$slug, $url));
423 }
424
425 // Modifies the feed link to add the language parameter
426 function feed_link($url, $feed) {
427 return $GLOBALS['wp_rewrite']->using_permalinks() ? $this->add_language_to_link($url) : esc_url(home_url('?lang='.$this->curlang->slug.'&feed='.$feed));
428 }
429
430 // modifies the sql request for wp_get_archives an get_adjacent_post to filter by the current language
431 function posts_join($sql) {
432 return $sql . $GLOBALS['wpdb']->prepare(" INNER JOIN $wpdb->term_relationships ON object_id = ID");
433 }
434
435 // modifies the sql request for wp_get_archives and get_adjacent_post to filter by the current language
436 function posts_where($sql) {
437 return $sql . $GLOBALS['wpdb']->prepare(" AND term_taxonomy_id = %d", $this->curlang->term_taxonomy_id);
438 }
439
440 // modifies the author and date links to add the language parameter
441 function archive_link($link) {
442 return $GLOBALS['wp_rewrite']->using_permalinks() ?
443 $this->add_language_to_link($link) :
444 esc_url(str_replace($this->home.'/?', $this->home.'/?lang='.$this->curlang->slug.'&amp;', $link));
445 }
446
447 // returns the url of the translation (if exists) of the current page
448 function get_translation_url($language) {
449 global $wp_query, $wp_rewrite;
450 $qvars = $wp_query->query;
451 $hide = $this->options['default_lang'] == $language->slug && $this->options['hide_default'];
452
453 // is_single is set to 1 for attachment but no language is set
454 if (is_single() && !is_attachment() && $id = $this->get_post($wp_query->queried_object_id, $language))
455 $url = get_permalink($id);
456
457 // page for posts
458 elseif (get_option('show_on_front') == 'page' && isset($wp_query->queried_object_id) && $wp_query->queried_object_id == $this->page_for_posts)
459 $url = get_permalink($this->get_post($this->page_for_posts, $language));
460
461 elseif (is_page() && $id = $this->get_post($wp_query->queried_object_id, $language))
462 $url = $hide && $id == $this->get_post($this->page_on_front, $language) ? $this->home : _get_page_link($id);
463
464 elseif ( !is_tax('language') && (is_category() || is_tag() || is_tax ()) ) {
465 $term = get_queried_object();
466 $lang = $this->get_term_language($term->term_id);
467 $taxonomy = $term->taxonomy;
468
469 if ($language->slug == $lang->slug)
470 $url = get_term_link($term, $taxonomy); // self link
471 elseif ($link_id = $this->get_translation('term', $term->term_id, $language))
472 $url = get_term_link(get_term($link_id, $taxonomy), $taxonomy);
473 }
474
475 // don't test if there are existing translations before creating the url as it would be very expensive in sql queries
476 elseif(is_archive()) {
477 if ($wp_rewrite->using_permalinks()) {
478 $base = $this->options['rewrite'] ? '/' : '/language/';
479 $base = $hide ? '' : $base.$language->slug;
480 $base = $this->home.$base.'/';
481
482 if (is_author())
483 $url = esc_url($base.'author/'.$qvars['author_name'].'/');
484
485 if (is_year())
486 $url = esc_url($base.$qvars['year'].'/');
487
488 if (is_month())
489 $url = esc_url($base.$qvars['year'].'/'.$qvars['monthnum'].'/');
490
491 if (is_day())
492 $url = esc_url($base.$qvars['year'].'/'.$qvars['monthnum'].'/'.$qvars['day'].'/');
493 }
494 else
495 $url = $hide ? remove_query_arg('lang') : add_query_arg('lang', $language->slug);
496 }
497
498 elseif (is_home() || is_tax('language') )
499 $url = $hide ? $this->home : get_term_link($language, 'language');
500
501 return isset($url) ? $url : null;
502 }
503
504 // filters the nav menus according to the current language
505 function wp_nav_menu_args($args) {
506 if (!$args['menu'] && $args['theme_location']) {
507 $menu_lang = get_option('polylang_nav_menus');
508 $args['menu'] = $menu_lang[$args['theme_location']][$this->curlang->slug];
509 }
510 return $args;
511 }
512
513 // filters the widgets according to the current language
514 function widget_display_callback($instance, $widget, $args) {
515 $widget_lang = get_option('polylang_widgets');
516 // don't display if a language filter is set and this is not the current one
517 return isset($widget_lang[$widget->id]) && $widget_lang[$widget->id] && $widget_lang[$widget->id] != $this->curlang->slug ? false : $instance;
518 }
519
520 // adds the language switcher at the end of the menu
521 function wp_nav_menu_items($items, $args) {
522 $menu_lang = get_option('polylang_nav_menus');
523 return $menu_lang[$args->theme_location]['switcher'] ?
524 $items . $this->the_languages(array(
525 'menu' => 1,
526 'show_names' => $menu_lang[$args->theme_location]['show_names'],
527 'show_flags' => $menu_lang[$args->theme_location]['show_flags'],
528 'force_home' => $menu_lang[$args->theme_location]['force_home'],
529 'echo' => 0)) :
530 $items;
531 }
532
533 // corrects some issues on front page and post pages nav menus items
534 function wp_nav_menu_objects($menu_items, $args) {
535 global $wp_query;
536
537 // corrects classes in the menu for posts page
538 // FIXME check for child pages
539 if ($wp_query->is_posts_page) {
540 $classes = array('current-menu-item', 'current_page_item', 'current_page_parent');
541 foreach($menu_items as $item) {
542 $item->classes = array_diff($item->classes, $classes);
543 if ($item->object_id == $this->get_post($this->page_for_posts, $this->curlang))
544 $item->classes = array_merge($item->classes, $classes);
545 }
546 }
547
548 foreach($menu_items as $item) {
549 if ($item->object == 'page')
550 $item->url = _get_page_link($item->object_id); // avoids bad link on translated front page
551 }
552
553 return $menu_items;
554 }
555
556 // corrects the output of the function for translated home
557 function wp_page_menu($menu, $args) {
558 global $wp_query;
559
560 // add current_page_item class to posts page
561 if ($wp_query->is_posts_page) {
562 $id = $this->get_post($this->page_for_posts, $this->curlang);
563 $menu = str_replace('<li class="page_item page-item-'.$id.'">', '<li class="page_item page-item-'.$id.' current_page_item">', $menu);
564 }
565
566 // add current_page_item class to home page
567 // normally only the homepage has no class. note the space in <li >
568 if ($this->is_front_page() && !is_paged())
569 $menu = str_replace('<li >', '<li class="current_page_item">', $menu);
570
571 // remove the 2nd occurrence of homepage (when translated)
572 if ($this->page_on_front) {
573 $id = $this->get_post($this->page_on_front, $this->curlang);
574 $url = _get_page_link($id);
575 $title = apply_filters( 'the_title', get_page($id)->post_title);
576 $menu = str_replace('<li class="page_item page-item-'.$id.'"><a href="'.$url.'">'.$title.'</a></li>', '', $menu);
577 $menu = str_replace('<li class="page_item page-item-'.$id.' current_page_item"><a href="'.$url.'">'.$title.'</a></li>', '', $menu);
578 }
579 return $menu;
580 }
581
582 // translates widget titles
583 function widget_title($title) {
584 return __($title, 'pll_string');
585 }
586
587 // translates site title and tagline
588 function bloginfo($output, $show) {
589 return in_array($show, array('', 'name', 'description')) ? __($output, 'pll_string') : $output;
590 }
591
592 // acts as is_front_page but knows about translated front page
593 function is_front_page() {
594 if ('posts' == get_option('show_on_front') && is_home())
595 return true;
596 elseif ('page' == get_option('show_on_front') && $this->page_on_front && is_page($this->get_post($this->page_on_front, $this->get_current_language())))
597 return true;
598 elseif(is_tax('language'))
599 return true;
600 else
601 return false;
602 }
603
604 // loads front page template on translated front page
605 function template_include($template) {
606 return ($this->is_front_page() && $front_page = get_front_page_template()) ? $front_page : $template;
607 }
608
609 // filters the home url to get the right language
610 function home_url($url) {
611 if ( !(did_action('template_redirect') && rtrim($url,'/') == rtrim($this->home,'/')) )
612 return $url;
613
614 // don't like this but at least for WP_Widget_Categories::widget, it seems to be the only solution
615 // FIXME are there other exceptions ?
616 foreach (debug_backtrace() as $trace) {
617 $exceptions = $trace['function'] == 'get_pagenum_link' ||
618 $trace['function'] == 'get_author_posts_url' ||
619 $trace['function'] == 'get_search_form' ||
620 (isset($trace['file']) && strpos($trace['file'], 'searchform.php')) ||
621 ($trace['function'] == 'widget' && $trace['class'] == 'WP_Widget_Categories');
622 if ($exceptions)
623 return $url;
624 }
625 return $this->get_home_url($this->curlang);
626 }
627
628 // returns the home url in the right language
629 function get_home_url($language) {
630 if ($this->options['default_lang'] == $language->slug && $this->options['hide_default'])
631 return trailingslashit($this->home);
632
633 // a static page is used as front page
634 if ($this->page_on_front && $id = $this->get_post($this->page_on_front, $language))
635 $url = _get_page_link($id);
636
637 return isset($url) ? $url : get_term_link($language, 'language');
638 }
639
640 // adds 'lang_url' as possible value to the 'show' parameter of bloginfo to display the home url in the correct language
641 // FIXME not tested
642 function bloginfo_url($output, $show) {
643 if ($show == 'lang_url') {
644 $url = $this->get_home_url($this->curlang);
645 $output = isset($url) ? $url : $this->home;
646 }
647 return $output;
648 }
649
650 // displays the language switcher
651 function the_languages($args = '') {
652 $defaults = array(
653 'dropdown' => 0, // display as list and not as dropdown
654 'echo' => 1, // echoes the list
655 'hide_if_empty' => 1, // hides languages with no posts (or pages)
656 'menu' => '0', // not for nav menu
657 'show_flags' => 0, // don't show flags
658 'show_names' => 1, // show language names
659 'force_home' => 0, // tries to find a translation (available only if display != dropdown)
660 'hide_if_no_translation' => 0, // don't hide the link if there is no translation
661 'hide_current' => 0, // don't hide current language
662 );
663 extract(wp_parse_args($args, $defaults));
664
665 $output = '';
666 $listlanguages = $this->get_languages_list($hide_if_empty);
667
668 foreach ($listlanguages as $language) {
669 if ($dropdown) {
670 $output .= sprintf("<option value='%s'%s>%s</option>\n",
671 esc_attr($language->slug),
672 $language->term_id == $this->curlang->term_id ? ' selected="selected"' : '',
673 esc_html($language->name)
674 );
675 }
676 else {
677 // hide current language
678 if ($this->curlang->term_id == $language->term_id && $hide_current)
679 continue;
680
681 $url = $force_home ? null : $this->get_translation_url($language);
682
683 // hide if no translation exists
684 if (!isset($url) && $hide_if_no_translation)
685 continue;
686
687 $url = isset($url) ? $url : $this->get_home_url($language); // if the page is not translated, link to the home page
688
689 $class = 'lang-item lang-item-'.esc_attr($language->term_id);
690 $class .= $language->term_id == $this->curlang->term_id ? ' current-lang' : '';
691 $class .= $menu ? ' menu-item' : '';
692
693 $flag = $show_flags ? $this->get_flag($language) : '';
694 $name = $show_names || !$show_flags ? esc_html($language->name) : '';
695
696 $output .= '<li class="'.$class.'"><a href="'.esc_url($url).'">'.($show_flags && $show_names ? $flag.'&nbsp;'.$name : $flag.$name)."</a></li>\n";
697 }
698 }
699
700 $output = $dropdown ? "<select name='lang_choice' id='lang_choice'>\n" . $output . "</select>\n" : $output;
701
702 if ($echo)
703 echo $output;
704 else
705 return $output;
706 }
707 }
708 ?>
709