PluginProbe
Polylang / 0.8.2
Polylang v0.8.2
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.8.2, at polylang.php

396 lines 15.5 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.8.2
6 Author: F. Demarle
7 Description: Adds multilingual capability to Wordpress
8 */
9
10 /* Copyright 2011-2012 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, published by
14 the Free Software Foundation, either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 */
26
27 define('POLYLANG_VERSION', '0.8.2');
28 define('PLL_MIN_WP_VERSION', '3.1');
29
30 define('POLYLANG_DIR', dirname(__FILE__)); // our directory
31 define('PLL_INC', POLYLANG_DIR.'/include');
32
33 define('POLYLANG_URL', WP_PLUGIN_URL.'/'.basename(POLYLANG_DIR)); // our url
34
35 if (!defined('PLL_LOCAL_DIR'))
36 define('PLL_LOCAL_DIR', WP_CONTENT_DIR.'/polylang'); // default directory to store user data such as custom flags
37
38 if (!defined('PLL_LOCAL_URL'))
39 define('PLL_LOCAL_URL', WP_CONTENT_URL.'/polylang'); // default url to access user data such as custom flags
40
41 if (!defined('PLL_DISPLAY_ABOUT'))
42 define('PLL_DISPLAY_ABOUT', true); // displays the "About Polylang" metabox by default
43
44 if (!defined('PLL_DISPLAY_ALL'))
45 define('PLL_DISPLAY_ALL', false); // diplaying posts & terms with undefined language is disabled by default (unsupported since 0.7)
46
47 if (!defined('PLL_FILTER_HOME_URL'))
48 define('PLL_FILTER_HOME_URL', true); // filters the home url (to return the homepage in the right langage) by default
49
50 if (!defined('PLL_SYNC'))
51 define('PLL_SYNC', true); // synchronisation is enabled by default
52
53 require_once(PLL_INC.'/base.php');
54 require_once(PLL_INC.'/widget.php');
55 require_once(PLL_INC.'/calendar.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 are going to deactivate the plugin avoids breaking rewrite rules
69 if (isset($_GET['action']) && $_GET['action'] == 'deactivate' && isset($_GET['plugin']) && $_GET['plugin'] == 'polylang/polylang.php')
70 return;
71
72 // manages plugin upgrade
73 add_filter('upgrader_post_install', array(&$this, 'post_upgrade'));
74 add_action('admin_init', array(&$this, 'admin_init'));
75
76 // plugin and widget initialization
77 add_action('init', array(&$this, 'init'));
78 add_action('widgets_init', array(&$this, 'widgets_init'));
79 add_action('wp_loaded', array(&$this, 'prepare_rewrite_rules'), 20); // after Polylang_base::add_post_types_taxonomies
80
81 // separate admin and frontend
82 if (is_admin() && isset($_GET['page']) && $_GET['page'] == 'mlang') {
83 require_once(PLL_INC.'/admin-base.php');
84 require_once(PLL_INC.'/admin.php');
85 $polylang = new Polylang_Admin();
86 }
87 elseif (is_admin()) {
88 require_once(PLL_INC.'/admin-base.php');
89 require_once(PLL_INC.'/admin-filters.php');
90 $polylang = new Polylang_Admin_Filters();
91 }
92 else {
93 require_once(PLL_INC.'/core.php');
94 $polylang = new Polylang_Core();
95 }
96
97 // loads the API
98 require_once(PLL_INC.'/api.php');
99 }
100
101 // plugin activation for multisite
102 function activate() {
103 global $wp_version, $wpdb;
104 $style = '<p style = "font-family: sans-serif; font-size: 12px; color: #333; margin: -5px">%s</p>';
105
106 if (version_compare($wp_version, PLL_MIN_WP_VERSION , '<'))
107 die (sprintf($style, sprintf(__('You are using WordPress %s. Polylang requires at least WordPress %s.', 'polylang'), $wp_version, PLL_MIN_WP_VERSION)));
108
109 // check if it is a network activation - if so, run the activation function for each blog
110 if (is_multisite() && isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
111 foreach ($wpdb->get_col($wpdb->prepare("SELECT blog_id FROM $wpdb->blogs")) as $blog_id) {
112 switch_to_blog($blog_id);
113 $r = $this->_activate();
114 }
115 restore_current_blog();
116 }
117 else
118 $r = $this->_activate();
119
120 if (!$r)
121 die (sprintf($style, __('For some reasons, Polylang could not create a table in your database.', 'polylang')));
122 }
123
124 // plugin activation
125 function _activate() {
126 // create the termmeta table - not provided by WP by default - if it does not already exists
127 // uses exactly the same model as other meta tables to be able to use access functions provided by WP
128 global $wpdb;
129 $charset_collate = empty($wpdb->charset) ? '' : "DEFAULT CHARACTER SET $wpdb->charset";
130 $charset_collate .= empty($wpdb->collate) ? '' : " COLLATE $wpdb->collate";
131 $table = $wpdb->prefix . 'termmeta';
132
133 $r = $wpdb->query("CREATE TABLE IF NOT EXISTS $table (
134 meta_id bigint(20) unsigned NOT NULL auto_increment,
135 term_id bigint(20) unsigned NOT NULL default '0',
136 meta_key varchar(255) default NULL,
137 meta_value longtext,
138 PRIMARY KEY (meta_id),
139 KEY term_id (term_id),
140 KEY meta_key (meta_key)
141 ) $charset_collate;");
142
143 if ($r === false)
144 return false;
145
146 // codex tells to use the init action to call register_taxonomy but I need it now for my rewrite rules
147 register_taxonomy('language', null , array('label' => false, 'query_var'=>'lang'));
148
149 // defines default values for options in case this is the first installation
150 $options = get_option('polylang');
151 if (!$options) {
152 $options['browser'] = 1; // default language for the front page is set by browser preference
153 $options['rewrite'] = 1; // remove /language/ in permalinks (was the opposite before 0.7.2)
154 $options['hide_default'] = 0; // do not remove URL language information for default language
155 $options['force_lang'] = 0; // do not add URL language information when useless
156 $options['redirect_lang'] = 0; // do not redirect the language page to the homepage
157 }
158 $options['version'] = POLYLANG_VERSION;
159 update_option('polylang', $options);
160
161 // add our rewrite rules
162 $this->add_post_types_taxonomies();
163 $this->prepare_rewrite_rules();
164 flush_rewrite_rules();
165 return true;
166 }
167
168 // plugin deactivation for multisite
169 function deactivate() {
170 global $wpdb;
171
172 // check if it is a network deactivation - if so, run the deactivation function for each blog
173 if (is_multisite() && isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
174 foreach ($wpdb->get_col($wpdb->prepare("SELECT blog_id FROM $wpdb->blogs")) as $blog_id) {
175 switch_to_blog($blog_id);
176 $this->_deactivate();
177 }
178 restore_current_blog();
179 }
180 else
181 $this->_deactivate();
182 }
183
184 // plugin deactivation
185 function _deactivate() {
186 flush_rewrite_rules();
187 }
188
189 // restores the local_flags directory after upgrade from version 0.5.1 or older
190 function post_upgrade() {
191 // nothing to restore
192 if (!@is_dir($upgrade_dir = WP_CONTENT_DIR . '/upgrade/polylang/local_flags'))
193 return true;
194
195 // don't move if the directory is empty
196 $contents = @scandir($upgrade_dir);
197 if (is_array($contents) && ($files = array_diff($contents, array(".", "..", ".DS_Store", "_notes", "Thumbs.db"))) && empty($files))
198 return true;
199
200 // move the directory to wp-content
201 if (!@rename($upgrade_dir, PLL_LOCAL_DIR))
202 return new WP_Error('polylang_restore_error', sprintf('%s<br />%s',
203 __('Error: Restore of local flags failed!', 'polylang'),
204 sprintf(__('Please move your local flags from %s to %s', 'polylang'), esc_html($upgrade_dir), '<strong>'.esc_html(PLL_LOCAL_DIR).'</strong>')
205 ));
206
207 @rmdir(WP_CONTENT_DIR . '/upgrade/polylang');
208 return true;
209 }
210
211 // upgrades from old translation used up to V0.4.4 to new model used in V0.5+
212 function upgrade_translations($type, $ids) {
213 $listlanguages = $this->get_languages_list();
214 foreach ($ids as $id) {
215 $lang = call_user_func(array(&$this, 'get_'.$type.'_language'), $id);
216 if (!$lang)
217 continue;
218
219 $tr = array();
220 foreach ($listlanguages as $language) {
221 if ($meta = get_metadata($type, $id, '_lang-'.$language->slug, true))
222 $tr[$language->slug] = $meta;
223 }
224
225 if (!empty($tr)) {
226 $tr = serialize(array_merge(array($lang->slug => $id), $tr));
227 update_metadata($type, $id, '_translations', $tr);
228 }
229 }
230 }
231
232 // manage upgrade even when it is done manually
233 function admin_init() {
234 $options = get_option('polylang');
235 if (version_compare($options['version'], POLYLANG_VERSION, '<')) {
236
237 if (version_compare($options['version'], '0.4', '<'))
238 $options['hide_default'] = 0; // option introduced in 0.4
239
240 // translation model changed in V0.5
241 if (version_compare($options['version'], '0.5', '<')) {
242 $ids = get_posts(array('numberposts' => -1, 'fields' => 'ids', 'post_type' => 'any', 'post_status' => 'any'));
243 $this->upgrade_translations('post', $ids);
244 $ids = get_terms($this->taxonomies, array('get' => 'all', 'fields' => 'ids'));
245 $this->upgrade_translations('term', $ids);
246 }
247
248 // translation model changed in V0.5
249 // deleting the old one has been delayed in V0.6 (just in case...)
250 if (version_compare($options['version'], '0.6', '<')) {
251 $listlanguages = $this->get_languages_list();
252
253 $ids = get_posts(array('numberposts'=> -1, 'fields' => 'ids', 'post_type'=>'any', 'post_status'=>'any'));
254 foreach ($ids as $id) {
255 foreach ($listlanguages as $lang)
256 delete_post_meta($id, '_lang-'.$lang->slug);
257 }
258
259 $ids = get_terms($this->taxonomies, array('get' => 'all', 'fields' => 'ids'));
260 foreach ($ids as $id) {
261 foreach ($listlanguages as $lang)
262 delete_metadata('term', $id, '_lang-'.$lang->slug);
263 }
264 }
265
266 if (version_compare($options['version'], '0.7', '<'))
267 $options['force_lang'] = 0; // option introduced in 0.7
268
269 // string translation storage model changed and option added in 0.8
270 if (version_compare($options['version'], '0.8dev1', '<')) {
271 if (function_exists('base64_decode')) {
272 $mo = new MO();
273 foreach ($this->get_languages_list() as $language) {
274 $reader = new POMO_StringReader(base64_decode(get_option('polylang_mo'.$language->term_id)));
275 $mo->import_from_reader($reader);
276 $this->mo_export($mo, $language);
277 }
278 }
279 $options['redirect_lang'] = 0; // option introduced in 0.8
280 }
281
282 if (version_compare($options['version'], '0.8.2', '<'))
283 flush_rewrite_rules(); // rewrite rules have been modified in 0.7.1 & 0.7.2 & 0.8 & 0.8.1 & 0.8.2
284
285 $options['version'] = POLYLANG_VERSION;
286 update_option('polylang', $options);
287 }
288 }
289
290 // some initialization
291 function init() {
292 global $wpdb;
293 $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb
294 $options = get_option('polylang');
295
296 // registers the language taxonomy
297 // codex: use the init action to call this function
298 // object types will be set later once all custom post types are registered
299 register_taxonomy('language', null, array(
300 'label' => false,
301 'public' => false, // avoid displaying the 'like post tags text box' in the quick edit
302 'query_var'=>'lang',
303 'update_count_callback' => '_update_post_term_count'));
304
305 // optionaly removes 'language' in permalinks so that we get http://www.myblog/en/ instead of http://www.myblog/language/en/
306 if ($options['rewrite'])
307 add_permastruct('language', '%language%', array('with_front' => false));
308
309 load_plugin_textdomain('polylang', false, basename(POLYLANG_DIR).'/languages'); // plugin i18n
310 }
311
312 // registers our widgets
313 function widgets_init() {
314 register_widget('Polylang_Widget');
315
316 // overwrites the calendar widget to filter posts by language
317 unregister_widget('WP_Widget_Calendar');
318 register_widget('Polylang_Widget_Calendar');
319 }
320
321 // complete our taxonomy and add rewrite rules filters once custom post types and taxonomies are registered (normally in init)
322 function prepare_rewrite_rules() {
323 foreach ($this->post_types as $post_type)
324 register_taxonomy_for_object_type('language', $post_type);
325
326 // don't modify the rules if there is no languages created yet
327 if (!$this->get_languages_list())
328 return;
329
330 $types = array_merge(array('post', 'date', 'root', 'comments', 'search', 'author', 'page'), array_keys($GLOBALS['wp_rewrite']->extra_permastructs));
331 $types = apply_filters('pll_rewrite_rules', $types); // allow plugins to add rewrite rules to the language filter
332 foreach ($types as $type)
333 add_filter($type . '_rewrite_rules', array(&$this, 'rewrite_rules'));
334
335 add_filter('rewrite_rules_array', array(&$this, 'rewrite_rules')); // needed for post type archives
336 }
337
338 // the rewrite rules !
339 // always make sure the default language is at the end in case the language information is hidden for default language
340 // thanks to brbrbr http://wordpress.org/support/topic/plugin-polylang-rewrite-rules-not-correct
341 function rewrite_rules($rules) {
342 // suppress the rules created by WordPress for our taxonomy
343 if (($current_filter = current_filter()) == 'language_rewrite_rules')
344 return array();
345
346 $options = get_option('polylang');
347 $always_rewrite = in_array(str_replace('_rewrite_rules', '', $current_filter), array('date', 'root', 'comments', 'author', 'post_format'));
348 $newrules = array();
349
350 foreach ($this->get_languages_list() as $language)
351 if (!$options['hide_default'] || $options['default_lang'] != $language->slug)
352 $languages[] = $language->slug;
353
354 if (isset($languages))
355 $slug = $options['rewrite'] ? '('.implode('|', $languages).')/' : 'language/('.implode('|', $languages).')/';
356
357 foreach ($rules as $key => $rule) {
358 // we don't need the lang parameter for post types and taxonomies
359 // moreover adding it would create issues for pages and taxonomies
360 if ($options['force_lang'] && in_array(str_replace('_rewrite_rules', '', $current_filter), array_merge($this->post_types, $this->taxonomies))) {
361 if (isset($slug))
362 $newrules[$slug.$key] = str_replace(array('[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]'),
363 array('[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]'), $rule); // hopefully it is sufficient !
364
365 if ($options['hide_default'])
366 $newrules[$key] = $rules[$key];
367
368 unset($rules[$key]); // now useless
369 }
370
371 // rewrite rules filtered by language
372 elseif ($always_rewrite || strpos($rule, 'post_type=') || ($current_filter != 'rewrite_rules_array' && $options['force_lang'])) {
373 if (isset($slug))
374 $newrules[$slug.$key] = str_replace(array('[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?'),
375 array('[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&'), $rule); // hopefully it is sufficient !
376
377 if ($options['hide_default'])
378 $newrules[$key] = str_replace('?', '?lang='.$options['default_lang'].'&', $rule);
379
380 unset($rules[$key]); // now useless
381 }
382 }
383
384 // the home rewrite rule
385 if ($current_filter == 'root_rewrite_rules' && isset($slug))
386 $newrules[$slug.'?$'] = 'index.php?lang=$matches[1]';
387
388 return $newrules + $rules;
389 }
390
391 } // class Polylang
392
393 if (class_exists("Polylang"))
394 new Polylang();
395 ?>
396