PluginProbe
Polylang / 1.0.1
Polylang v1.0.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 1.0.1, at polylang.php

390 lines 15.2 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.0.1
6 Author: F. 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.0.1');
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', WP_PLUGIN_URL.'/'.basename(POLYLANG_DIR)); // our url
45
46 if (!defined('PLL_LOCAL_URL'))
47 define('PLL_LOCAL_URL', WP_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');
51
52 require_once(PLL_INC.'/base.php');
53
54 // controls the plugin, deals with activation, deactivation, upgrades, initialization as well as rewrite rules
55 class Polylang extends Polylang_Base {
56
57 function __construct() {
58 parent::__construct();
59 global $polylang; // globalize the variable to access it in the API
60
61 // manages plugin activation and deactivation
62 register_activation_hook( __FILE__, array(&$this, 'activate'));
63 register_deactivation_hook( __FILE__, array(&$this, 'deactivate'));
64
65 // stopping here if we upgraded from a too old version
66 if (($options = get_option('polylang')) && version_compare($options['version'], '0.8', '<')) {
67 add_action('all_admin_notices', array(&$this, 'admin_notices'));
68 return;
69 }
70
71 // stopping here if we are going to deactivate the plugin (avoids breaking rewrite rules)
72 if (isset($_GET['action']) && $_GET['action'] == 'deactivate' && isset($_GET['plugin']) && $_GET['plugin'] == 'polylang/polylang.php')
73 return;
74
75 // blog creation on multisite
76 add_action('wpmu_new_blog', array(&$this, 'wpmu_new_blog'));
77
78 // manages plugin upgrade
79 add_action('admin_init', array(&$this, 'admin_init'));
80
81 // plugin and widget initialization
82 add_action('setup_theme', array(&$this, 'init'), 1);
83 add_action('widgets_init', array(&$this, 'widgets_init'));
84 add_action('wp_loaded', array(&$this, 'prepare_rewrite_rules'), 5); // after Polylang_base::add_post_types_taxonomies
85
86 // separate admin and frontend
87 if (is_admin() && isset($_GET['page']) && $_GET['page'] == 'mlang') {
88 require_once(PLL_INC.'/admin-base.php');
89 require_once(PLL_INC.'/admin.php');
90 $polylang = new Polylang_Admin();
91 }
92
93 // avoid loading polylang admin filters for frontend ajax requests if 'pll_load_front' is set (thanks to g100g)
94 elseif (defined('DOING_CRON') || (is_admin() && !(defined('DOING_AJAX') && isset($_REQUEST['pll_load_front'])))) {
95 require_once(PLL_INC.'/admin-base.php');
96 require_once(PLL_INC.'/admin-filters.php');
97 $polylang = new Polylang_Admin_Filters();
98 }
99
100 else {
101 require_once(PLL_INC.'/core.php');
102 $polylang = new Polylang_Core();
103 }
104
105 // loads the API
106 require_once(PLL_INC.'/api.php');
107
108 // WPML API + wpml-config.xml
109 if (!defined('PLL_WPML_COMPAT') || PLL_WPML_COMPAT)
110 require_once(PLL_INC.'/wpml-compat.php');
111
112 // extra code for compatibility with some plugins
113 if (!defined('PLL_PLUGINS_COMPAT') || PLL_PLUGINS_COMPAT)
114 require_once(PLL_INC.'/plugins-compat.php');
115 }
116
117 // plugin activation for multisite
118 function activate() {
119 global $wp_version, $wpdb;
120 load_plugin_textdomain('polylang', false, basename(POLYLANG_DIR).'/languages'); // plugin i18n
121
122 if (version_compare($wp_version, PLL_MIN_WP_VERSION , '<'))
123 die (sprintf('<p style = "font-family: sans-serif; font-size: 12px; color: #333; margin: -5px">%s</p>',
124 sprintf(__('You are using WordPress %s. Polylang requires at least WordPress %s.', 'polylang'),
125 esc_html($wp_version),
126 PLL_MIN_WP_VERSION
127 )
128 ));
129
130 // check if it is a network activation - if so, run the activation function for each blog
131 if (is_multisite() && isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
132 foreach ($wpdb->get_col("SELECT blog_id FROM $wpdb->blogs") as $blog_id) {
133 switch_to_blog($blog_id);
134 $this->_activate();
135 }
136 restore_current_blog();
137 }
138 else
139 $this->_activate();
140 }
141
142 // plugin activation
143 function _activate() {
144 // create the termmeta table - not provided by WP by default - if it does not already exists
145 // uses exactly the same model as other meta tables to be able to use access functions provided by WP
146 global $wpdb;
147 $charset_collate = empty($wpdb->charset) ? '' : "DEFAULT CHARACTER SET $wpdb->charset";
148 $charset_collate .= empty($wpdb->collate) ? '' : " COLLATE $wpdb->collate";
149 $table = $wpdb->prefix . 'termmeta';
150
151 $r = $wpdb->query("
152 CREATE TABLE IF NOT EXISTS $table (
153 meta_id bigint(20) unsigned NOT NULL auto_increment,
154 term_id bigint(20) unsigned NOT NULL default '0',
155 meta_key varchar(255) default NULL,
156 meta_value longtext,
157 PRIMARY KEY (meta_id),
158 KEY term_id (term_id),
159 KEY meta_key (meta_key)
160 ) $charset_collate;");
161
162 if ($r === false)
163 die (sprintf(
164 '<p style = "font-family: sans-serif; font-size: 12px; color: #333; margin: -5px">%s</p>',
165 __('For some reasons, Polylang could not create a table in your database.', 'polylang')
166 ));
167
168 // codex tells to use the init action to call register_taxonomy but I need it now for my rewrite rules
169 register_taxonomy('language', null , array('label' => false, 'query_var'=>'lang'));
170
171 // defines default values for options in case this is the first installation
172 $options = get_option('polylang');
173 if (!$options) {
174 $options['browser'] = 1; // default language for the front page is set by browser preference
175 $options['rewrite'] = 1; // remove /language/ in permalinks (was the opposite before 0.7.2)
176 $options['hide_default'] = 0; // do not remove URL language information for default language
177 $options['force_lang'] = 0; // do not add URL language information when useless
178 $options['redirect_lang'] = 0; // do not redirect the language page to the homepage
179 $options['media_support'] = 1; // support languages and translation for media by default
180 $options['sync'] = array_keys($this->list_metas_to_sync()); // synchronisation is enabled by default
181 $options['post_types'] = array_values(get_post_types(array('_builtin' => false, 'show_ui => true')));
182 $options['taxonomies'] = array_values(get_taxonomies(array('_builtin' => false, 'show_ui => true')));
183 }
184 $options['version'] = POLYLANG_VERSION;
185
186 if (update_option('polylang', $options)) {
187 // add our rewrite rules
188 $this->add_post_types_taxonomies();
189 $this->prepare_rewrite_rules();
190 flush_rewrite_rules();
191 }
192 }
193
194 // plugin deactivation for multisite
195 function deactivate() {
196 global $wpdb;
197
198 // check if it is a network deactivation - if so, run the deactivation function for each blog
199 if (is_multisite() && isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
200 foreach ($wpdb->get_col("SELECT blog_id FROM $wpdb->blogs") as $blog_id) {
201 switch_to_blog($blog_id);
202 $this->_deactivate();
203 }
204 restore_current_blog();
205 }
206 else
207 $this->_deactivate();
208 }
209
210 // plugin deactivation
211 function _deactivate() {
212 flush_rewrite_rules();
213 }
214
215 // blog creation on multisite
216 function wpmu_new_blog($blog_id) {
217 switch_to_blog($blog_id);
218 $r = $this->_activate();
219 restore_current_blog();
220 }
221
222 // displays a notice when ugrading from a too old version
223 function admin_notices() {
224 printf(
225 '<div class="error"><p>%s</p><p>%s</p></div>',
226 __('Polylang has been deactivated because you upgraded from a too old version.', 'polylang'),
227 sprintf(
228 __('Please upgrade first to %s before ugrading to %s.', 'polylang'),
229 '<strong>0.9.8</strong>',
230 POLYLANG_VERSION
231 )
232 );
233 }
234
235 // manage upgrade even when it is done manually
236 function admin_init() {
237 $options = get_option('polylang');
238 if (version_compare($options['version'], POLYLANG_VERSION, '<')) {
239
240 if (version_compare($options['version'], '0.9', '<'))
241 $options['sync'] = defined('PLL_SYNC') && !PLL_SYNC ? 0 : 1; // the option replaces PLL_SYNC in 0.9
242
243 if (version_compare($options['version'], '1.0', '<')) {
244 // the option replaces PLL_MEDIA_SUPPORT in 1.0
245 $options['media_support'] = defined('PLL_MEDIA_SUPPORT') && !PLL_MEDIA_SUPPORT ? 0 : 1;
246
247 // split the synchronization options in 1.0
248 $options['sync'] = empty($options['sync']) ? array() : array_keys($this->list_metas_to_sync());
249
250 // set default values for post types and taxonomies to translate
251 $options['post_types'] = array_values(get_post_types(array('_builtin' => false, 'show_ui => true')));
252 $options['taxonomies'] = array_values(get_taxonomies(array('_builtin' => false, 'show_ui => true')));
253
254 flush_rewrite_rules(); // rewrite rules have been modified in 1.0
255 }
256
257 $options['version'] = POLYLANG_VERSION;
258 update_option('polylang', $options);
259 }
260 }
261
262 // some initialization
263 function init() {
264 global $wpdb;
265 $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb
266 $options = get_option('polylang');
267
268 if (is_admin())
269 load_plugin_textdomain('polylang', false, basename(POLYLANG_DIR).'/languages'); // plugin i18n, only needed for backend
270
271 // registers the language taxonomy
272 // codex: use the init action to call this function
273 // object types will be set later once all custom post types are registered
274 register_taxonomy('language', null, array(
275 'labels' => array(
276 'name' => __('Languages', 'polylang'),
277 'singular_name' => __('Language', 'polylang'),
278 'all_items' => __('All languages', 'polylang'),
279 ),
280 'public' => false, // avoid displaying the 'like post tags text box' in the quick edit
281 'query_var'=>'lang',
282 'update_count_callback' => '_update_post_term_count'
283 ));
284
285 // optionaly removes 'language' in permalinks so that we get http://www.myblog/en/ instead of http://www.myblog/language/en/
286 // language information always in front of the uri ('with_front' => false)
287 // the 3rd parameter structure has been modified in WP 3.4
288 add_permastruct('language', $options['rewrite'] ? '%language%' : 'language/%language%',
289 version_compare($GLOBALS['wp_version'], '3.4' , '<') ? false : array('with_front' => false));
290 }
291
292 // registers our widgets
293 function widgets_init() {
294 require_once(PLL_INC.'/widget.php');
295 register_widget('Polylang_Widget');
296
297 // overwrites the calendar widget to filter posts by language
298 if (!defined('PLL_WIDGET_CALENDAR') || PLL_WIDGET_CALENDAR) {
299 require_once(PLL_INC.'/calendar.php'); // loads this only now otherwise it breaks widgets not registered in a widgets_init hook
300 unregister_widget('WP_Widget_Calendar');
301 register_widget('Polylang_Widget_Calendar');
302 }
303 }
304
305 // complete our taxonomy and add rewrite rules filters once custom post types and taxonomies are registered (normally in init)
306 function prepare_rewrite_rules() {
307 foreach ($this->post_types as $post_type)
308 register_taxonomy_for_object_type('language', $post_type);
309
310 // don't modify the rules if there is no languages created yet
311 if (!$this->get_languages_list())
312 return;
313
314 $types = array_values(array_merge($this->post_types, $this->taxonomies)); // supported post types and taxonomies
315 $types = array_merge(array('date', 'root', 'comments', 'search', 'author', 'language', 'post_format'), $types);
316 $types = apply_filters('pll_rewrite_rules', $types); // allow plugins to add rewrite rules to the language filter
317
318 foreach ($types as $type)
319 add_filter($type . '_rewrite_rules', array(&$this, 'rewrite_rules'));
320
321 add_filter('rewrite_rules_array', array(&$this, 'rewrite_rules')); // needed for post type archives
322 }
323
324 // the rewrite rules !
325 // always make sure the default language is at the end in case the language information is hidden for default language
326 // thanks to brbrbr http://wordpress.org/support/topic/plugin-polylang-rewrite-rules-not-correct
327 function rewrite_rules($rules) {
328 $filter = str_replace('_rewrite_rules', '', current_filter());
329
330 // suppress the rules created by WordPress for our taxonomy
331 if ($filter == 'language')
332 return array();
333
334 global $wp_rewrite;
335 $options = get_option('polylang');
336 $always_rewrite = in_array($filter, array('date', 'root', 'comments', 'author', 'post_format'));
337 $newrules = array();
338
339 foreach ($this->get_languages_list() as $language)
340 if (!$options['hide_default'] || $options['default_lang'] != $language->slug)
341 $languages[] = $language->slug;
342
343 if (isset($languages))
344 $slug = $wp_rewrite->root . ($options['rewrite'] ? '' : 'language/') . '('.implode('|', $languages).')/';
345
346 foreach ($rules as $key => $rule) {
347 // we don't need the lang parameter for post types and taxonomies
348 // moreover adding it would create issues for pages and taxonomies
349 if ($options['force_lang'] && in_array($filter, array_merge($this->post_types, $this->taxonomies))) {
350 if (isset($slug))
351 $newrules[$slug.str_replace($wp_rewrite->root, '', $key)] = str_replace(
352 array('[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]'),
353 array('[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]'),
354 $rule
355 ); // hopefully it is sufficient!
356
357 if ($options['hide_default']) {
358 $newrules[$key] = $rules[$key];
359 // unset only if we hide the code for the default language as check_language_code_in_url will do its job in other cases
360 unset($rules[$key]);
361 }
362 }
363
364 // rewrite rules filtered by language
365 elseif ($always_rewrite || (strpos($rule, 'post_type=') && !strpos($rule, 'name=')) || ($filter != 'rewrite_rules_array' && $options['force_lang'])) {
366 if (isset($slug))
367 $newrules[$slug.str_replace($wp_rewrite->root, '', $key)] = str_replace(
368 array('[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?'),
369 array('[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&'),
370 $rule
371 ); // should be enough!
372
373 if ($options['hide_default'])
374 $newrules[$key] = str_replace('?', '?lang='.$options['default_lang'].'&', $rule);
375
376 unset($rules[$key]); // now useless
377 }
378 }
379
380 // the home rewrite rule
381 if ($filter == 'root' && isset($slug))
382 $newrules[$slug.'?$'] = $wp_rewrite->index.'?lang=$matches[1]';
383
384 return $newrules + $rules;
385 }
386
387 } // class Polylang
388
389 new Polylang();
390