PluginProbe
Polylang / 1.1.6
Polylang v1.1.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 / polylang.php

polylang.php in Polylang 1.1.6, at polylang.php

455 lines 17.9 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://polylang.wordpress.com/
5 Version: 1.1.6
6 Author: Frédéric Demarle
7 Description: Adds multilingual capability to WordPress
8 Text Domain: polylang
9 Domain Path: /languages
10 */
11
12 /*
13 * Copyright 2011-2013 F. Demarle
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
28 * MA 02110-1301, USA.
29 *
30 */
31
32 define('POLYLANG_VERSION', '1.1.6');
33 define('PLL_MIN_WP_VERSION', '3.1');
34
35 define('POLYLANG_DIR', dirname(__FILE__)); // our directory
36 define('PLL_INC', POLYLANG_DIR.'/include');
37
38 if (!defined('PLL_LOCAL_DIR'))
39 define('PLL_LOCAL_DIR', WP_CONTENT_DIR.'/polylang'); // default directory to store user data such as custom flags
40
41 if (file_exists(PLL_LOCAL_DIR.'/pll-config.php'))
42 include_once(PLL_LOCAL_DIR.'/pll-config.php'); // includes local config file if exists
43
44 define('POLYLANG_URL', plugins_url('/'.basename(POLYLANG_DIR))); // our url. Don't use WP_PLUGIN_URL http://wordpress.org/support/topic/ssl-doesnt-work-properly
45
46 if (!defined('PLL_LOCAL_URL'))
47 define('PLL_LOCAL_URL', content_url('/polylang')); // default url to access user data such as custom flags
48
49 if (!defined('PLL_COOKIE'))
50 define('PLL_COOKIE', 'pll_language'); // cookie name. no cookie will be used if set to false
51
52 if (!defined('PLL_SEARCH_FORM_JS') && !version_compare($GLOBALS['wp_version'], '3.6', '<'))
53 define('PLL_SEARCH_FORM_JS', false); // the search form js is no more needed in WP 3.6+ except if the search form is hardcoded elsewhere than in searchform.php
54
55 require_once(PLL_INC.'/base.php');
56
57 // controls the plugin, deals with activation, deactivation, upgrades, initialization as well as rewrite rules
58 class Polylang extends Polylang_Base {
59
60 function __construct() {
61 parent::__construct();
62 global $polylang; // globalize the variable to access it in the API
63
64 // manages plugin activation and deactivation
65 register_activation_hook( __FILE__, array(&$this, 'activate'));
66 register_deactivation_hook( __FILE__, array(&$this, 'deactivate'));
67
68 // stopping here if we upgraded from a too old version
69 if ($this->options && version_compare($this->options['version'], '0.8', '<')) {
70 add_action('all_admin_notices', array(&$this, 'admin_notices'));
71 return;
72 }
73
74 // stopping here if we are going to deactivate the plugin (avoids breaking rewrite rules)
75 if (isset($_GET['action'], $_GET['plugin']) && $_GET['action'] == 'deactivate' && $_GET['plugin'] == 'polylang/polylang.php')
76 return;
77
78 // blog creation on multisite
79 add_action('wpmu_new_blog', array(&$this, 'wpmu_new_blog'));
80
81 // manages plugin upgrade
82 add_action('admin_init', array(&$this, 'admin_init'));
83
84 // plugin and widget initialization
85 add_action('setup_theme', array(&$this, 'init'), 1);
86 add_action('widgets_init', array(&$this, 'widgets_init'));
87 add_action('wp_loaded', array(&$this, 'prepare_rewrite_rules'), 5); // after Polylang_base::add_post_types_taxonomies
88
89 // separate admin and frontend
90 if (is_admin() && isset($_GET['page']) && $_GET['page'] == 'mlang') {
91 require_once(PLL_INC.'/admin-base.php');
92 require_once(PLL_INC.'/admin.php');
93 $polylang = new Polylang_Admin();
94 }
95
96 elseif ($this->is_admin) {
97 require_once(PLL_INC.'/admin-base.php');
98 require_once(PLL_INC.'/admin-filters.php');
99 $polylang = new Polylang_Admin_Filters();
100 }
101
102 else {
103 require_once(PLL_INC.'/core.php');
104 $polylang = new Polylang_Core();
105
106 // auto translate posts and terms ids in term
107 if (!defined('PLL_AUTO_TRANSLATE') || PLL_AUTO_TRANSLATE)
108 require_once(PLL_INC.'/auto-translate.php');
109 }
110
111 // loads the API
112 require_once(PLL_INC.'/api.php');
113
114 // nav menus
115 require_once(PLL_INC.'/nav-menu.php');
116
117 // WPML API + wpml-config.xml
118 if (!defined('PLL_WPML_COMPAT') || PLL_WPML_COMPAT)
119 require_once(PLL_INC.'/wpml-compat.php');
120
121 // extra code for compatibility with some plugins
122 if (!defined('PLL_PLUGINS_COMPAT') || PLL_PLUGINS_COMPAT)
123 require_once(PLL_INC.'/plugins-compat.php');
124 }
125
126 // plugin activation for multisite
127 function activate() {
128 global $wp_version, $wpdb;
129 load_plugin_textdomain('polylang', false, basename(POLYLANG_DIR).'/languages'); // plugin i18n
130
131 if (version_compare($wp_version, PLL_MIN_WP_VERSION , '<'))
132 die (sprintf('<p style = "font-family: sans-serif; font-size: 12px; color: #333; margin: -5px">%s</p>',
133 sprintf(__('You are using WordPress %s. Polylang requires at least WordPress %s.', 'polylang'),
134 esc_html($wp_version),
135 PLL_MIN_WP_VERSION
136 )
137 ));
138
139 // check if it is a network activation - if so, run the activation function for each blog
140 if (is_multisite() && isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
141 foreach ($wpdb->get_col("SELECT blog_id FROM $wpdb->blogs") as $blog_id) {
142 switch_to_blog($blog_id);
143 $this->_activate();
144 }
145 restore_current_blog();
146 }
147 else
148 $this->_activate();
149 }
150
151 // plugin activation
152 function _activate() {
153 // create the termmeta table - not provided by WP by default - if it does not already exists
154 // uses exactly the same model as other meta tables to be able to use access functions provided by WP
155 global $wpdb;
156 $charset_collate = empty($wpdb->charset) ? '' : "DEFAULT CHARACTER SET $wpdb->charset";
157 $charset_collate .= empty($wpdb->collate) ? '' : " COLLATE $wpdb->collate";
158 $table = $wpdb->prefix . 'termmeta';
159
160 $r = $wpdb->query("
161 CREATE TABLE IF NOT EXISTS $table (
162 meta_id bigint(20) unsigned NOT NULL auto_increment,
163 term_id bigint(20) unsigned NOT NULL default '0',
164 meta_key varchar(255) default NULL,
165 meta_value longtext,
166 PRIMARY KEY (meta_id),
167 KEY term_id (term_id),
168 KEY meta_key (meta_key)
169 ) $charset_collate;");
170
171 if ($r === false)
172 die (sprintf(
173 '<p style = "font-family: sans-serif; font-size: 12px; color: #333; margin: -5px">%s</p>',
174 __('For some reasons, Polylang could not create a table in your database.', 'polylang')
175 ));
176
177 // codex tells to use the init action to call register_taxonomy but I need it now for my rewrite rules
178 register_taxonomy('language', null , array('label' => false, 'query_var'=>'lang'));
179
180 // defines default values for options in case this is the first installation
181 if (!get_option('polylang')) {
182 $options['browser'] = 1; // default language for the front page is set by browser preference
183 $options['rewrite'] = 1; // remove /language/ in permalinks (was the opposite before 0.7.2)
184 $options['hide_default'] = 0; // do not remove URL language information for default language
185 $options['force_lang'] = 0; // do not add URL language information when useless
186 $options['redirect_lang'] = 0; // do not redirect the language page to the homepage
187 $options['media_support'] = 1; // support languages and translation for media by default
188 $options['sync'] = array_keys($this->list_metas_to_sync()); // synchronisation is enabled by default
189 $options['post_types'] = array_values(get_post_types(array('_builtin' => false, 'show_ui => true')));
190 $options['taxonomies'] = array_values(get_taxonomies(array('_builtin' => false, 'show_ui => true')));
191 $options['version'] = POLYLANG_VERSION;
192
193 update_option('polylang', $options);
194 }
195
196 // add our rewrite rules
197 $this->add_post_types_taxonomies();
198 $this->prepare_rewrite_rules();
199 flush_rewrite_rules();
200 }
201
202 // plugin deactivation for multisite
203 function deactivate() {
204 global $wpdb;
205
206 // check if it is a network deactivation - if so, run the deactivation function for each blog
207 if (is_multisite() && isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
208 foreach ($wpdb->get_col("SELECT blog_id FROM $wpdb->blogs") as $blog_id) {
209 switch_to_blog($blog_id);
210 $this->_deactivate();
211 }
212 restore_current_blog();
213 }
214 else
215 $this->_deactivate();
216 }
217
218 // plugin deactivation
219 function _deactivate() {
220 flush_rewrite_rules();
221 }
222
223 // blog creation on multisite
224 function wpmu_new_blog($blog_id) {
225 switch_to_blog($blog_id);
226 $r = $this->_activate();
227 restore_current_blog();
228 }
229
230 // displays a notice when ugrading from a too old version
231 function admin_notices() {
232 load_plugin_textdomain('polylang', false, basename(POLYLANG_DIR).'/languages');
233 printf(
234 '<div class="error"><p>%s</p><p>%s</p></div>',
235 __('Polylang has been deactivated because you upgraded from a too old version.', 'polylang'),
236 sprintf(
237 __('Please upgrade first to %s before ugrading to %s.', 'polylang'),
238 '<strong>0.9.8</strong>',
239 POLYLANG_VERSION
240 )
241 );
242 }
243
244 // manage upgrade even when it is done manually
245 function admin_init() {
246
247 if (version_compare($this->options['version'], POLYLANG_VERSION, '<')) {
248
249 if (version_compare($this->options['version'], '0.9', '<'))
250 $this->options['sync'] = defined('PLL_SYNC') && !PLL_SYNC ? 0 : 1; // the option replaces PLL_SYNC in 0.9
251
252 if (version_compare($this->options['version'], '1.0', '<')) {
253 // the option replaces PLL_MEDIA_SUPPORT in 1.0
254 $this->options['media_support'] = defined('PLL_MEDIA_SUPPORT') && !PLL_MEDIA_SUPPORT ? 0 : 1;
255
256 // split the synchronization options in 1.0
257 $this->options['sync'] = empty($this->options['sync']) ? array() : array_keys($this->list_metas_to_sync());
258
259 // set default values for post types and taxonomies to translate
260 $this->options['post_types'] = array_values(get_post_types(array('_builtin' => false, 'show_ui => true')));
261 $this->options['taxonomies'] = array_values(get_taxonomies(array('_builtin' => false, 'show_ui => true')));
262
263 flush_rewrite_rules(); // rewrite rules have been modified in 1.0
264 }
265
266 if (version_compare($this->options['version'], '1.0.2', '<'))
267 // set the option again in case it was not in 1.0
268 if (!isset($this->options['media_support']))
269 $this->options['media_support'] = defined('PLL_MEDIA_SUPPORT') && !PLL_MEDIA_SUPPORT ? 0 : 1;
270
271 if (version_compare($this->options['version'], '1.1', '<')) {
272 // update strings register with icl_register_string
273 $strings = get_option('polylang_wpml_strings');
274 if ($strings) {
275 foreach ($strings as $key => $string)
276 $strings[$key]['icl'] = 1;
277 update_option('polylang_wpml_strings', $strings);
278 }
279
280 // move polylang_widgets options
281 if ($widgets = get_option('polylang_widgets')) {
282 $this->options['widgets'] = $widgets;
283 delete_option('polylang_widgets');
284 }
285
286 // update nav menus
287 if ($menu_lang = get_option('polylang_nav_menus')) {
288
289 foreach ($menu_lang as $location => $arr) {
290 if (!in_array($location, array_keys(get_registered_nav_menus())))
291 continue;
292
293 $switch_options = array_slice($arr, -5, 5);
294 $translations = array_diff_key($arr, $switch_options);
295 $has_switcher = array_shift($switch_options);
296
297 foreach ($this->get_languages_list() as $lang) {
298 $menu_locations[$location.(pll_default_language() == $lang->slug ? '' : '#' . $lang->slug)] = empty($translations[$lang->slug]) ? 0 : $translations[$lang->slug];
299
300 // create the menu items
301 if (!empty($has_switcher)) {
302 $menu_item_db_id = wp_update_nav_menu_item($translations[$lang->slug], 0, array(
303 'menu-item-title' => __('Language switcher', 'polylang'),
304 'menu-item-url' => '#pll_switcher',
305 'menu-item-status' => 'publish'
306 ));
307
308 update_post_meta($menu_item_db_id, '_pll_menu_item', $switch_options);
309 }
310 }
311 }
312
313 if (!empty($menu_locations))
314 set_theme_mod('nav_menu_locations', $menu_locations);
315
316 delete_option('polylang_nav_menus');
317 }
318 }
319
320 $this->options['version'] = POLYLANG_VERSION;
321 update_option('polylang', $this->options);
322 }
323 }
324
325 // some initialization
326 function init() {
327 global $wpdb;
328 $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb
329
330 if ($this->is_admin)
331 load_plugin_textdomain('polylang', false, basename(POLYLANG_DIR).'/languages'); // plugin i18n, only needed for backend
332
333 // registers the language taxonomy
334 // codex: use the init action to call this function
335 // object types will be set later once all custom post types are registered
336 register_taxonomy('language', null, array(
337 'labels' => array(
338 'name' => __('Languages', 'polylang'),
339 'singular_name' => __('Language', 'polylang'),
340 'all_items' => __('All languages', 'polylang'),
341 ),
342 'public' => false, // avoid displaying the 'like post tags text box' in the quick edit
343 'query_var' => 'lang',
344 'update_count_callback' => '_update_post_term_count'
345 ));
346
347 // optionaly removes 'language' in permalinks so that we get http://www.myblog/en/ instead of http://www.myblog/language/en/
348 // language information always in front of the uri ('with_front' => false)
349 // the 3rd parameter structure has been modified in WP 3.4
350 add_permastruct('language', $this->options['rewrite'] ? '%language%' : 'language/%language%',
351 version_compare($GLOBALS['wp_version'], '3.4' , '<') ? false : array('with_front' => false));
352 }
353
354 // registers our widgets
355 function widgets_init() {
356 require_once(PLL_INC.'/widget.php');
357 register_widget('Polylang_Widget');
358
359 // overwrites the calendar widget to filter posts by language
360 if (!defined('PLL_WIDGET_CALENDAR') || PLL_WIDGET_CALENDAR) {
361 require_once(PLL_INC.'/calendar.php'); // loads this only now otherwise it breaks widgets not registered in a widgets_init hook
362 unregister_widget('WP_Widget_Calendar');
363 register_widget('Polylang_Widget_Calendar');
364 }
365 }
366
367 // complete our taxonomy and add rewrite rules filters once custom post types and taxonomies are registered (normally in init)
368 function prepare_rewrite_rules() {
369 foreach ($this->post_types as $post_type)
370 register_taxonomy_for_object_type('language', $post_type);
371
372 // don't modify the rules if there is no languages created yet
373 if (!$this->get_languages_list())
374 return;
375
376 $types = array_values(array_merge($this->post_types, $this->taxonomies)); // supported post types and taxonomies
377 $types = array_merge(array('date', 'root', 'comments', 'search', 'author', 'language', 'post_format'), $types);
378 $types = apply_filters('pll_rewrite_rules', $types); // allow plugins to add rewrite rules to the language filter
379
380 foreach ($types as $type)
381 add_filter($type . '_rewrite_rules', array(&$this, 'rewrite_rules'));
382
383 add_filter('rewrite_rules_array', array(&$this, 'rewrite_rules')); // needed for post type archives
384 }
385
386 // the rewrite rules !
387 // always make sure the default language is at the end in case the language information is hidden for default language
388 // thanks to brbrbr http://wordpress.org/support/topic/plugin-polylang-rewrite-rules-not-correct
389 function rewrite_rules($rules) {
390 $filter = str_replace('_rewrite_rules', '', current_filter());
391
392 // suppress the rules created by WordPress for our taxonomy
393 if ($filter == 'language')
394 return array();
395
396 global $wp_rewrite;
397 $always_rewrite = in_array($filter, array('date', 'root', 'comments', 'author', 'post_format'));
398 $newrules = array();
399
400 foreach ($this->get_languages_list() as $language)
401 if (!$this->options['hide_default'] || $this->options['default_lang'] != $language->slug)
402 $languages[] = $language->slug;
403
404 if (isset($languages))
405 $slug = $wp_rewrite->root . ($this->options['rewrite'] ? '' : 'language/') . '('.implode('|', $languages).')/';
406
407 // for custom post type archives
408 $cpts = array_intersect($this->post_types, get_post_types(array('_builtin' => false)));
409 $cpts = $cpts ? '#post_type=('.implode('|', $cpts).')#' : '';
410
411 foreach ($rules as $key => $rule) {
412 // we don't need the lang parameter for post types and taxonomies
413 // moreover adding it would create issues for pages and taxonomies
414 if ($this->options['force_lang'] && in_array($filter, array_merge($this->post_types, $this->taxonomies))) {
415 if (isset($slug))
416 $newrules[$slug.str_replace($wp_rewrite->root, '', $key)] = str_replace(
417 array('[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]'),
418 array('[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]'),
419 $rule
420 ); // hopefully it is sufficient!
421
422 if ($this->options['hide_default']) {
423 $newrules[$key] = $rules[$key];
424 // unset only if we hide the code for the default language as check_language_code_in_url will do its job in other cases
425 unset($rules[$key]);
426 }
427 }
428
429 // rewrite rules filtered by language
430 elseif ($always_rewrite || ($cpts && preg_match($cpts, $rule) && !strpos($rule, 'name=')) || ($filter != 'rewrite_rules_array' && $this->options['force_lang'])) {
431 if (isset($slug))
432 $newrules[$slug.str_replace($wp_rewrite->root, '', $key)] = str_replace(
433 array('[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?'),
434 array('[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&'),
435 $rule
436 ); // should be enough!
437
438 if ($this->options['hide_default'])
439 $newrules[$key] = str_replace('?', '?lang='.$this->options['default_lang'].'&', $rule);
440
441 unset($rules[$key]); // now useless
442 }
443 }
444
445 // the home rewrite rule
446 if ($filter == 'root' && isset($slug))
447 $newrules[$slug.'?$'] = $wp_rewrite->index.'?lang=$matches[1]';
448
449 return $newrules + $rules;
450 }
451
452 } // class Polylang
453
454 new Polylang();
455