PluginProbe
Polylang / 0.1
Polylang v0.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 / polylang.php

polylang.php in Polylang 0.1, at polylang.php

655 lines 23.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Polylang
4 Plugin URI: http://wordpress.org/extend/plugins/polylang/
5 Version: 0.1
6 Author: F. Demarle
7 Description: Adds multilingual capability to Wordpress
8 */
9
10 /* Copyright 2011 F. Demarle
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License, version 2, as
14 published by the Free Software Foundation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26 define('MULTILANG_VERSION', '0.1');
27 require_once(dirname(__FILE__).'/base.php');
28 require_once(dirname(__FILE__).'/admin.php');
29 require_once(dirname(__FILE__).'/widget.php');
30
31 class Polylang extends Polylang_Base {
32 var $curlang;
33 var $list_textdomains = array();
34 var $search_form_filter = false;
35
36 function __construct() {
37
38 // manages plugin activation and deactivation
39 register_activation_hook( __FILE__, array(&$this, 'activate') );
40 register_deactivation_hook( __FILE__, array(&$this, 'deactivate') );
41
42 // plugin and widget initialization
43 add_action('init', array(&$this,'init'));
44 add_action('widgets_init', array(&$this,'widgets_init'));
45
46 // rewrite rules
47 add_filter('rewrite_rules_array', array(&$this,'rewrite_rules_array' ));
48
49 // filters categories and post tags by language
50 add_filter('get_terms', array(&$this,'get_terms'), 10, 3);
51
52 if (is_admin())
53 new Polylang_Admin();
54 else {
55 // text domain management
56 add_filter('locale', array(&$this,'get_locale'));
57 add_filter('override_load_textdomain', array(&$this,'mofile'), 10, 3);
58 add_action('wp', array(&$this,'load_textdomains'));
59
60 // filters posts according to the language
61 add_filter('pre_get_posts', array(&$this,'pre_get_posts'));
62
63 // meta in the html head section
64 remove_action('wp_head', 'rel_canonical');
65 add_action('wp_head', array(&$this,'wp_head'));
66
67 // prevents redirection of the homepage
68 add_filter('redirect_canonical', array(&$this,'redirect_canonical'), 10, 2);
69
70 // adds javascript at the end of the document
71 add_action('wp_print_footer_scripts', array(&$this,'wp_print_footer_scripts'));
72
73 // adds the language information in the search form
74 add_filter('get_search_form', array(&$this,'get_search_form'));
75
76 // filters the pages according to the current language
77 add_filter('get_pages', array(&$this,'get_pages'), 10, 2);
78
79 // rewrites feed links to filter them by language
80 add_filter('feed_link', array(&$this,'feed_link'), 10, 2);
81
82 // rewrites archives links to filter them by language
83 add_filter('getarchives_join', array(&$this,'posts_join'));
84 add_filter('getarchives_where', array(&$this,'posts_where'));
85 add_filter('get_archives_link', array(&$this,'get_archives_link'));
86
87 // rewrites next and previous post links to filter them by language
88 add_filter('get_previous_post_join', array(&$this,'posts_join'));
89 add_filter('get_next_post_join', array(&$this,'posts_join'));
90 add_filter('get_previous_post_where', array(&$this,'posts_where'));
91 add_filter('get_next_post_where', array(&$this,'posts_where'));
92
93 // allows a new value for the 'show' parameter to display the homepage url according to the current language
94 add_filter('bloginfo_url', array(&$this,'bloginfo_url'), 10, 2);
95
96 // Template tags
97 add_action('the_languages', array(&$this,'the_languages'));
98 }
99 }
100
101 // plugin activation
102 function activate() {
103 // create the termmeta table - not provided by WP by default - if it does not already exists
104 // uses exactly the same model as other meta tables to be able to use access functions provided by WP
105 global $wpdb;
106 $charset_collate = '';
107 if ( ! empty($wpdb->charset) )
108 $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
109 if ( ! empty($wpdb->collate) )
110 $charset_collate .= " COLLATE $wpdb->collate";
111
112 $table = $wpdb->prefix . 'termmeta';
113
114 $tables = $wpdb->get_results("show tables like '$table'");
115 if (!count($tables))
116 $wpdb->query("CREATE TABLE $table (
117 meta_id bigint(20) unsigned NOT NULL auto_increment,
118 term_id bigint(20) unsigned NOT NULL default '0',
119 meta_key varchar(255) default NULL,
120 meta_value longtext,
121 PRIMARY KEY (meta_id),
122 KEY term_id (term_id),
123 KEY meta_key (meta_key)
124 ) $charset_collate;");
125
126 // codex tells to use the init action to call register_taxonomy but I need it now for my rewrite rules
127 register_taxonomy('language', 'post', array('label' => false, 'query_var'=>'lang'));
128
129 // defines default values for options in case this is the first installation
130 $options = get_option('polylang');
131 if (!$options) {
132 $options['browser'] = 1; // default language for the front page is set by browser preference
133 $options['rewrite'] = 0; // do not remove /language/ in permalinks
134 }
135 $options['version'] = MULTILANG_VERSION; // do not manage versions yet but prepare for it
136 update_option('polylang', $options);
137
138 // add our rewrite rules
139 global $wp_rewrite;
140 $wp_rewrite->flush_rules();
141 }
142
143 // plugin deactivation
144 function deactivate() {
145 // delete our rewrite rules
146 remove_filter('rewrite_rules_array', array(&$this,'rewrite_rules_array' ));
147 global $wp_rewrite;
148 $wp_rewrite->flush_rules();
149 }
150
151 // some initialization
152 function init() {
153 global $wpdb;
154 $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb
155
156 // registers the language taxonomy
157 // codex: use the init action to call this function
158 register_taxonomy('language', 'post', array(
159 'label' => false,
160 'query_var'=>'lang',
161 'update_count_callback' => '_update_post_term_count'));
162
163 // optionaly removes 'language' in permalinks so that we get http://www.myblog/en/ instead of http://www.myblog/language/en/
164 // the simple line of code is inspired by the WP No Category Base plugin : http://wordpresssupplies.com/wordpress-plugins/no-category-base/
165 $options = get_option('polylang');
166 if ($options['rewrite']) {
167 global $wp_rewrite;
168 $wp_rewrite->extra_permastructs['language'][0] = '%language%';
169 }
170
171 load_plugin_textdomain('polylang', false, dirname(plugin_basename( __FILE__ ))); // plugin i18n
172 }
173
174 // registers our widget
175 function widgets_init() {
176 register_widget('Polylang_Widget');
177 }
178
179 // rewrites rules if pretty permalinks are used
180 function rewrite_rules_array($rules) {
181 $options = get_option('polylang');
182 $newrules = array();
183 $listlanguages = $this->get_languages_list();
184
185 // modifies the rules created by WordPress when '/language/' is removed in permalinks
186 if ($options['rewrite']) {
187 foreach ($listlanguages as $language) {
188 $newrules[$language->slug.'/feed/(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]';
189 $newrules[$language->slug.'/(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]';
190 $newrules[$language->slug.'/page/?([0-9]{1,})/?$'] = 'index.php?lang='.$language->slug.'&paged=$matches[1]';
191 $newrules[$language->slug.'/?$'] = 'index.php?lang='.$language->slug;
192 }
193 unset($rules['([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?lang=$matches[1]&feed=$matches[2]
194 unset($rules['([^/]+)/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?lang=$matches[1]&feed=$matches[2]
195 unset($rules['([^/]+)/page/?([0-9]{1,})/?$']); // => index.php?lang=$matches[1]&paged=$matches[2]
196 unset($rules['([^/]+)/?$']); // => index.php?lang=$matches[1]
197 }
198
199 $options['rewrite'] ? $base = '' : $base = 'language/';
200
201 // rewrite rules for comments feed filtered by language
202 foreach ($listlanguages as $language) {
203 $newrules[$base.$language->slug.'/comments/feed/(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]&withcomments=1';
204 $newrules[$base.$language->slug.'/comments/(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]&withcomments=1';
205 }
206 unset($rules['comments/feed/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?&feed=$matches[1]&withcomments=1
207 unset($rules['comments/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?&feed=$matches[1]&withcomments=1
208
209 // rewrite rules for archives filtered by language
210 foreach ($rules as $key => $rule) {
211 $is_archive = strpos($rule, 'year=') && !(
212 strpos($rule, 'p=') ||
213 strpos($rule, 'name=') ||
214 strpos($rule, 'page=') ||
215 strpos($rule, 'cpage=') );
216
217 if ($is_archive) {
218 foreach ($listlanguages as $language)
219 $newrules[$base.$language->slug.'/'.$key] = str_replace('?', '?lang='.$language->slug.'&', $rule);
220
221 unset($rules[$key]); // now useless
222 }
223 }
224
225 return $newrules + $rules;
226 }
227
228 // filters categories and post tags by language when needed (both in admin panels and frontend
229 function get_terms($terms, $taxonomies, $args) {
230 if (is_admin()) {
231 $screen = get_current_screen();
232 if (isset($screen))
233 // does nothing in the Categories, Post tags, Languages an Posts* admin panels
234 if ($screen->base == 'edit-tags' || $screen->base == 'toplevel_page_mlang' || $screen->base == 'edit')
235 return $terms;
236
237 // *FIXME I want all categories in the dropdown list and only the ones in the right language in the inline edit
238 // It seems that I need javascript to get the post_id as inline edit data are manipulated in inline-edit-post.js
239 }
240
241 // does nothing except on categories and post tags
242 if ( !in_array('category', $taxonomies) && !in_array('post_tag', $taxonomies) )
243 return $terms;
244
245 $lang = $this->get_current_language();
246 if ($lang) {
247 $slug = $lang->slug;
248 foreach($terms as $key => $term) {
249 $lang = $this->get_term_language($term->term_id);
250 if (!$lang || ($lang->slug) != $slug)
251 unset($terms[$key]); // remove terms with no language set or different language
252 }
253 }
254 return $terms;
255 }
256
257 // returns the language according to browser preference or the default language
258 function get_preferred_language() {
259 // check first is the user was already browsing this site
260 if ($lang = $this->get_language($_COOKIE['wordpress_polylang']))
261 return $lang;
262
263 // sets the browsing language according to the browser preferences
264 // code adapted from http://www.thefutureoftheweb.com/blog/use-accept-language-header
265 $options = get_option('polylang');
266 if ($options['browser']) {
267 $accept_langs = array();
268
269 if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
270 // break up string into pieces (languages and q factors)
271 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);
272
273 if (count($lang_parse[1])) {
274 $accept_langs = array_combine($lang_parse[1], $lang_parse[4]); // create a list like "en" => 0.8
275 // set default to 1 for any without q factor
276 foreach ($accept_langs as $accept_lang => $val) {
277 if ($val === '') $accept_langs[$accept_lang] = 1;
278 }
279 arsort($accept_langs, SORT_NUMERIC); // sort list based on value
280 }
281 }
282
283 // looks through sorted list and use first one that matches our language list
284 $listlanguages = $this->get_languages_list(true); // hides languages with no post
285 foreach ($accept_langs as $accept_lang => $val) {
286 foreach ($listlanguages as $language) {
287 if (strpos($accept_lang, $language->slug) === 0 && !isset($pref_lang)) {
288 $pref_lang = $this->get_language($language->slug);
289 }
290 }
291 }
292 } // options['browser']
293
294 // 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
295 if (!isset($pref_lang))
296 $pref_lang = $this->get_language($options['default_lang']);
297
298 return $pref_lang;
299 }
300
301 // returns the current language
302 function get_current_language() {
303 global $post_ID;
304
305 if($this->curlang)
306 return $this->curlang;
307
308 if (is_404())
309 return $this->get_preferred_language();
310
311 if (is_admin()) {
312 if (isset($post_ID))
313 $lang = $this->get_post_language($post_ID);
314
315 // trick to get the post number in the Post Tags metabox in the Edit Post screen (as $post_ID not defined)
316 $qvars = $this->get_referer_vars();
317 if (isset($qvars['post']))
318 $lang = $this->get_post_language($qvars['post']);
319 }
320 else {
321 $var = get_query_var('lang');
322 if ($var)
323 $lang = $this->get_language($var);
324 else {
325 $var = get_queried_object_id();
326 if ($var && is_single() || is_page())
327 $lang = $this->get_post_language($var);
328 else {
329 $var = get_query_var('cat');
330 if ($var)
331 $lang = $this->get_term_language($var);
332 else {
333 $var = get_query_var('tag_id');
334 if ($var)
335 $lang = $this->get_term_language($var);
336 }
337 }
338 }
339 }
340
341 return (isset($lang)) ? $lang : NULL;
342 }
343
344 // returns the locale based on current language
345 function get_locale($locale) {
346 if ($this->curlang)
347 $locale = $this->curlang->description;
348 return $locale;
349 }
350
351 // saves all text domains in a table for later usage
352 function mofile( $bool, $domain, $mofile) {
353 $this->list_textdomains[] = array ('mo' => $mofile, 'domain' => $domain);
354 return true; // prevents WP loading text domains as we will load them all later
355 }
356
357 // NOTE : I believe there are two ways for a plugin to force the WP language
358 // as done by xili_language and here : load text domains and reinitialize wp_locale with the action 'wp'
359 // as done by qtranslate : define the locale with the action 'plugins_loaded', but in this case, the language must be specified in the url.
360 function load_textdomains() {
361 // sets the current language and set a cookie to remember it
362 if ($this->curlang = $this->get_current_language())
363 setcookie('wordpress_polylang', $this->curlang->slug, time() + 31536000 /* 1 year */, COOKIEPATH, COOKIE_DOMAIN);
364
365 // our override_load_textdomain has done its job. let's remove it before calling load_textdomain
366 remove_filter('override_load_textdomain', array(&$this,'mofile'));
367
368 // now we can load text domains with the right language
369 foreach ($this->list_textdomains as $textdomain) {
370 $mo = preg_replace('#(.+)\/[a-zA-Z_]+\.mo$#', '$1/'.get_locale().'.mo', $textdomain['mo']); // replace the .mo file
371 load_textdomain( $textdomain['domain'], $mo);
372 }
373
374 global $wp_locale;
375 $wp_locale->init(); // reinitializes wp_locale for weekdays and months
376 }
377
378 // filters posts according to the language
379 function pre_get_posts($query) {
380
381 if (empty($query->query)) {
382
383 // sets the language according to browser preference or default language
384 $this->curlang = $this->get_preferred_language();
385
386 // redirect to the right translated page in case a static page is used as front page
387 $post_id = get_option('page_on_front');
388 if (isset($this->curlang) && $post_id) {
389 // a static page is used as front page
390 $language = $this->get_post_language($post_id);
391 if ($language->slug != $this->curlang->slug) {
392 // but the one defined in the "Reading Settings" panel is not in the right language, so let's redirect to the right one
393 $link_id = $this->get_translated_post($post_id, $this->curlang);
394 if ($link_id) {
395 $url = _get_page_link($link_id);
396 wp_redirect($url);
397 exit;
398 }
399 }
400 }
401 }
402
403 // filters recent posts to the current language
404 if ($query->is_home && $this->curlang)
405 $query->set('lang', $this->curlang->slug);
406
407 // remove pages from archives when the language is set
408 $qvars = $query->query_vars;
409 if (isset($qvars['m']) && isset($qvars['lang']))
410 $query->set('post_type', 'post');
411 }
412
413 function wp_head() {
414 // modifies the canonical link to the homepage
415 if (is_singular()) {
416 global $wp_the_query;
417
418 if ($id = $wp_the_query->get_queried_object_id()) {
419 if (is_page())
420 $link = _get_page_link($id); // ignores page_on_front unlike get_permalink
421 else
422 $link = get_permalink ($id);
423 echo "<link rel='canonical' href='$link' />\n";
424 }
425 }
426
427 // outputs references to translated pages (if exists) in the html head section
428 $listlanguages = $this->get_languages_list();
429 foreach ($listlanguages as $language) {
430 if ($language->slug != $this->curlang->slug) {
431 $url = $this->get_translation_url($language);
432 if ($url)
433 echo "<link hreflang='$language->slug' href='$url' rel='alternate' />\n";
434 }
435 }
436 }
437
438 // prevents redirection of the homepage
439 function redirect_canonical($redirect_url, $requested_url) {
440 if($requested_url == _get_page_link(get_option('page_on_front')))
441 return false;
442 return $redirect_url;
443 }
444
445 // adds some javascript workaround knowing it's not perfect...
446 function wp_print_footer_scripts() {
447 if ($this->curlang) {
448 $js = "<script type='text/javascript'>";
449
450 // modifies links to the homepage to filter by the right language
451 // since filtering home_url breaks things in the core and filtering bloginfo_url is not enough if the template uses home_url()
452 $url = rtrim(home_url(), '/');
453
454 if ($page = get_option('page_on_front'))
455 $newurl = _get_page_link($this->get_post($page, $this->curlang));
456 else
457 $newurl = get_term_link($this->curlang->slug, 'language');
458
459 $js .= "var e = document.getElementsByTagName('a');
460 for (var i = 0; i < e.length; i++) {
461 var href = e[i].href;
462 if (href == '$url' || href == '$url/') {
463 e[i].href = '$newurl';
464 }
465 }";
466
467 // modifies the search form since filtering get_search_form won't work if the template uses searchform.php
468 // don't use directly e[0] just in case there is somewhere else an element named 's'
469 // check before if the hidden input has not already been introduced by get_search_form
470 if (!$this->search_form_filter) {
471 $lang = $this->curlang->slug;
472 $js .= "e = document.getElementsByName('s');
473 for (i = 0; i < e.length; i++) {
474 if (e[i] == '[object HTMLInputElement]') {
475 var ih = document.createElement('input');
476 ih.type = 'hidden';
477 ih.name = 'lang';
478 ih.value = '$lang';
479 e[i].parentNode.appendChild(ih);
480 }
481 }";
482 }
483
484 $js .= "</script>";
485 echo $js;
486 }
487 }
488
489 // adds the language information in the search form
490 // FIXME does not work if searchform.php is used
491 function get_search_form($form) {
492 if ($form) {
493 $this->search_form_filter = true;
494 $form = str_replace('</form>', '<input type="hidden" name="lang" value="'.$this->curlang->slug.'" /></form>', $form);
495 }
496 return $form;
497 }
498
499 // filters the pages according to the current language
500 function get_pages($pages, $r) {
501 if (isset($this->curlang)) {
502 foreach ($pages as $key => $page) {
503 $lang = $this->get_post_language($page->ID);
504 if ($this->curlang != $lang)
505 unset($pages[$key]);
506 }
507 }
508 return $pages;
509 }
510
511 // Modifies the feed link to add the language parameter
512 // FIXME should be an option to do this ?
513 function feed_link($url, $feed) {
514 global $wp_rewrite;
515 $options = get_option('polylang');
516
517 if ($this->curlang) {
518 if ($wp_rewrite->using_permalinks()) {
519 $home = home_url();
520 $options['rewrite'] ? $base = '/' : $base = '/language/';
521 $url = str_replace($home, $home.$base.$this->curlang->slug, $url);
522 }
523 else {
524 if ($feed)
525 $url = home_url('?lang='.$this->curlang->slug.'&feed='.$feed);
526 }
527 }
528 return $url;
529 }
530
531 // modifies the sql request for wp_get_archives an get_adjacent_post to filter by the current language
532 function posts_join($sql) {
533 if ($this->curlang) {
534 global $wpdb;
535 $sql .= " INNER JOIN $wpdb->term_relationships ON object_id = ID";
536 }
537 return $sql;
538 }
539
540 // modifies the sql request for wp_get_archives and get_adjacent_post to filter by the current language
541 function posts_where($sql) {
542 if ($this->curlang) {
543 global $wpdb;
544 $lang_id = $this->curlang->term_id;
545 $sql .= " AND term_taxonomy_id = $lang_id";
546 }
547 return $sql;
548 }
549
550 // modifies the archives link to add the language parameter
551 function get_archives_link($link_html) {
552 if ($this->curlang) {
553 global $wp_rewrite;
554 $options = get_option('polylang');
555 $home = home_url();
556 if ($wp_rewrite->using_permalinks()) {
557 $options['rewrite'] ? $base = '/' : $base = '/language/';
558 $link_html = str_replace($home, $home.$base.$this->curlang->slug, $link_html);
559 }
560 else
561 $link_html = str_replace($home.'/?', $home.'/?lang='.$this->curlang->slug.'&amp;', $link_html);
562 }
563 return $link_html;
564 }
565
566 // returns the url of the translation (if exists) of the current page
567 function get_translation_url($language) {
568
569 if ( is_single()) {
570 $id = $this->get_post(get_the_ID(), $language);
571 if ($id)
572 $url = get_permalink($id);
573 }
574
575 elseif ( is_page() ) {
576 $id = $this->get_post(get_the_ID(), $language);
577 if ($id)
578 $url = _get_page_link($id);
579 }
580
581 elseif ( is_category() || is_tag() ) {
582 $term = get_queried_object();
583 $term_id = $term->term_id;
584 $taxonomy = $term->taxonomy;
585 $lang = $this->get_term_language($term_id);
586
587 if ($language->slug == $lang->slug)
588 $url = get_term_link($term->slug, $taxonomy); // self link
589 else {
590 $link_id = $this->get_translated_term($term_id, $language);
591 if ($link_id) {
592 $term = get_term($link_id,$taxonomy); // We need the slug for get_term_link
593 $url = get_term_link($term->slug, $taxonomy);
594 }
595 }
596 }
597
598 // FIXME for date links, if I simply modify the lang query, there is a risk that there is no posts (if all are not translated at this date)
599 // do nothing for now
600 elseif ( is_year() ) {
601 }
602
603 elseif ( is_month() ) {
604 }
605
606 elseif (is_home() || is_tax('language') )
607 $url = get_term_link($language->slug, 'language');
608
609 return isset($url) ? $url : null;
610 }
611
612 // returns the home url in the right language
613 function get_home_url($language) {
614 $post_id = get_option('page_on_front');
615 if ($post_id) {
616 // a static page is used as front page
617 $id = $this->get_post($post_id, $language);
618 if($id)
619 $url = _get_page_link($id);
620 }
621 return isset($url) ? $url : get_term_link($language->slug, 'language');
622 }
623
624 // adds 'lang_url' as possible value to the 'show' parameter of bloginfo to display the home url in the correct language
625 // FIXME not tested
626 function bloginfo_url($output, $show) {
627 if ($show == 'lang_url' && $this->curlang) {
628 $url = $this->get_home_url($this->curlang);
629 $output = isset($url) ? $url : home_url('/');
630 }
631 return $output;
632 }
633
634 // Template tag : Displays links to the current page in other languages
635 // Usage : do_action('the_languages');
636 function the_languages() {
637 $listlanguages = $this->get_languages_list(true); // hides languages with no posts
638 $output = "<ul>\n";
639 foreach ($listlanguages as $language) {
640 $url = $this->get_translation_url($language);
641 if (!isset($url))
642 $url = $this->get_home_url($language); // if the page is not translated, link to the home page
643 $output .= "<li><a href='$url'>".$language->name."</a></li>\n";
644 }
645 $output .= "</ul>\n";
646 echo $output;
647 }
648
649 } // class Polylang
650
651 if (class_exists("Polylang"))
652 new Polylang();
653
654 ?>
655