PluginProbe
Polylang / 0.8.1
Polylang v0.8.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.8.1, at polylang.php

386 lines 15.0 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.1
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.1');
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()) {
83 require_once(PLL_INC.'/admin.php');
84 $polylang = new Polylang_Admin();
85 }
86 else {
87 require_once(PLL_INC.'/core.php');
88 $polylang = new Polylang_Core();
89 }
90
91 // loads the API
92 require_once(PLL_INC.'/api.php');
93 }
94
95 // plugin activation for multisite
96 function activate() {
97 global $wp_version, $wpdb;
98 $style = '<p style = "font-family: sans-serif; font-size: 12px; color: #333; margin: -5px">%s</p>';
99
100 if (version_compare($wp_version, PLL_MIN_WP_VERSION , '<'))
101 die (sprintf($style, sprintf(__('You are using WordPress %s. Polylang requires at least WordPress %s.', 'polylang'), $wp_version, PLL_MIN_WP_VERSION)));
102
103 // check if it is a network activation - if so, run the activation function for each blog
104 if (is_multisite() && isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
105 foreach ($wpdb->get_col($wpdb->prepare("SELECT blog_id FROM $wpdb->blogs")) as $blog_id) {
106 switch_to_blog($blog_id);
107 $r = $this->_activate();
108 }
109 restore_current_blog();
110 }
111 else
112 $r = $this->_activate();
113
114 if (!$r)
115 die (sprintf($style, __('For some reasons, Polylang could not create a table in your database.', 'polylang')));
116 }
117
118 // plugin activation
119 function _activate() {
120 // create the termmeta table - not provided by WP by default - if it does not already exists
121 // uses exactly the same model as other meta tables to be able to use access functions provided by WP
122 global $wpdb;
123 $charset_collate = empty($wpdb->charset) ? '' : "DEFAULT CHARACTER SET $wpdb->charset";
124 $charset_collate .= empty($wpdb->collate) ? '' : " COLLATE $wpdb->collate";
125 $table = $wpdb->prefix . 'termmeta';
126
127 $r = $wpdb->query("CREATE TABLE IF NOT EXISTS $table (
128 meta_id bigint(20) unsigned NOT NULL auto_increment,
129 term_id bigint(20) unsigned NOT NULL default '0',
130 meta_key varchar(255) default NULL,
131 meta_value longtext,
132 PRIMARY KEY (meta_id),
133 KEY term_id (term_id),
134 KEY meta_key (meta_key)
135 ) $charset_collate;");
136
137 if ($r === false)
138 return false;
139
140 // codex tells to use the init action to call register_taxonomy but I need it now for my rewrite rules
141 register_taxonomy('language', null , array('label' => false, 'query_var'=>'lang'));
142
143 // defines default values for options in case this is the first installation
144 $options = get_option('polylang');
145 if (!$options) {
146 $options['browser'] = 1; // default language for the front page is set by browser preference
147 $options['rewrite'] = 1; // remove /language/ in permalinks (was the opposite before 0.7.2)
148 $options['hide_default'] = 0; // do not remove URL language information for default language
149 $options['force_lang'] = 0; // do not add URL language information when useless
150 $options['redirect_lang'] = 0; // do not redirect the language page to the homepage
151 }
152 $options['version'] = POLYLANG_VERSION;
153 update_option('polylang', $options);
154
155 // add our rewrite rules
156 $this->add_post_types_taxonomies();
157 $this->prepare_rewrite_rules();
158 $GLOBALS['wp_rewrite']->flush_rules();
159 return true;
160 }
161
162 // plugin deactivation for multisite
163 function deactivate() {
164 global $wpdb;
165
166 // check if it is a network deactivation - if so, run the deactivation function for each blog
167 if (is_multisite() && isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
168 foreach ($wpdb->get_col($wpdb->prepare("SELECT blog_id FROM $wpdb->blogs")) as $blog_id) {
169 switch_to_blog($blog_id);
170 $this->_deactivate();
171 }
172 restore_current_blog();
173 }
174 else
175 $this->_deactivate();
176 }
177
178 // plugin deactivation
179 function _deactivate() {
180 $GLOBALS['wp_rewrite']->flush_rules();
181 }
182
183 // restores the local_flags directory after upgrade from version 0.5.1 or older
184 function post_upgrade() {
185 // nothing to restore
186 if (!@is_dir($upgrade_dir = WP_CONTENT_DIR . '/upgrade/polylang/local_flags'))
187 return true;
188
189 // don't move if the directory is empty
190 $contents = @scandir($upgrade_dir);
191 if (is_array($contents) && ($files = array_diff($contents, array(".", "..", ".DS_Store", "_notes", "Thumbs.db"))) && empty($files))
192 return true;
193
194 // move the directory to wp-content
195 if (!@rename($upgrade_dir, PLL_LOCAL_DIR))
196 return new WP_Error('polylang_restore_error', sprintf('%s<br />%s',
197 __('Error: Restore of local flags failed!', 'polylang'),
198 sprintf(__('Please move your local flags from %s to %s', 'polylang'), esc_html($upgrade_dir), '<strong>'.esc_html(PLL_LOCAL_DIR).'</strong>')
199 ));
200
201 @rmdir(WP_CONTENT_DIR . '/upgrade/polylang');
202 return true;
203 }
204
205 // upgrades from old translation used up to V0.4.4 to new model used in V0.5+
206 function upgrade_translations($type, $ids) {
207 $listlanguages = $this->get_languages_list();
208 foreach ($ids as $id) {
209 $lang = call_user_func(array(&$this, 'get_'.$type.'_language'), $id);
210 if (!$lang)
211 continue;
212
213 $tr = array();
214 foreach ($listlanguages as $language) {
215 if ($meta = get_metadata($type, $id, '_lang-'.$language->slug, true))
216 $tr[$language->slug] = $meta;
217 }
218
219 if (!empty($tr)) {
220 $tr = serialize(array_merge(array($lang->slug => $id), $tr));
221 update_metadata($type, $id, '_translations', $tr);
222 }
223 }
224 }
225
226 // manage upgrade even when it is done manually
227 function admin_init() {
228 $options = get_option('polylang');
229 if (version_compare($options['version'], POLYLANG_VERSION, '<')) {
230
231 if (version_compare($options['version'], '0.4', '<'))
232 $options['hide_default'] = 0; // option introduced in 0.4
233
234 // translation model changed in V0.5
235 if (version_compare($options['version'], '0.5', '<')) {
236 $ids = get_posts(array('numberposts'=>-1, 'fields' => 'ids', 'post_type'=>'any', 'post_status'=>'any'));
237 $this->upgrade_translations('post', $ids);
238 $ids = get_terms($this->taxonomies, array('get'=>'all', 'fields'=>'ids'));
239 $this->upgrade_translations('term', $ids);
240 }
241
242 // translation model changed in V0.5
243 // deleting the old one has been delayed in V0.6 (just in case...)
244 if (version_compare($options['version'], '0.6', '<')) {
245 $listlanguages = $this->get_languages_list();
246
247 $ids = get_posts(array('numberposts'=> -1, 'fields' => 'ids', 'post_type'=>'any', 'post_status'=>'any'));
248 foreach ($ids as $id) {
249 foreach ($listlanguages as $lang)
250 delete_post_meta($id, '_lang-'.$lang->slug);
251 }
252
253 $ids = get_terms($this->taxonomies, array('get'=>'all', 'fields'=>'ids'));
254 foreach ($ids as $id) {
255 foreach ($listlanguages as $lang)
256 delete_metadata('term', $id, '_lang-'.$lang->slug);
257 }
258 }
259
260 if (version_compare($options['version'], '0.7', '<'))
261 $options['force_lang'] = 0; // option introduced in 0.7
262
263 // string translation storage model changed and option added in 0.8
264 if (version_compare($options['version'], '0.8dev1', '<')) {
265 if (function_exists('base64_decode')) {
266 $mo = new MO();
267 foreach ($this->get_languages_list() as $language) {
268 $reader = new POMO_StringReader(base64_decode(get_option('polylang_mo'.$language->term_id)));
269 $mo->import_from_reader($reader);
270 $this->mo_export($mo, $language);
271 }
272 }
273 $options['redirect_lang'] = 0; // option introduced in 0.8
274 }
275
276 if (version_compare($options['version'], '0.8.1', '<'))
277 $GLOBALS['wp_rewrite']->flush_rules(); // rewrite rules have been modified in 0.7.1 & 0.7.2 & 0.8 & 0.8.1
278
279 $options['version'] = POLYLANG_VERSION;
280 update_option('polylang', $options);
281 }
282 }
283
284 // some initialization
285 function init() {
286 global $wpdb;
287 $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb
288 $options = get_option('polylang');
289
290 // registers the language taxonomy
291 // codex: use the init action to call this function
292 // object types will be set later once all custom post types are registered
293 register_taxonomy('language', null, array(
294 'label' => false,
295 'public' => false, // avoid displaying the 'like post tags text box' in the quick edit
296 'query_var'=>'lang',
297 'rewrite' => array('slug' => $options['rewrite'] ? '' : 'language'), // http://www.myblog/en/ or http://www.myblog/language/en/ ?
298 'update_count_callback' => '_update_post_term_count'));
299
300 load_plugin_textdomain('polylang', false, basename(POLYLANG_DIR).'/languages'); // plugin i18n
301 }
302
303 // registers our widgets
304 function widgets_init() {
305 register_widget('Polylang_Widget');
306
307 // overwrites the calendar widget to filter posts by language
308 unregister_widget('WP_Widget_Calendar');
309 register_widget('Polylang_Widget_Calendar');
310 }
311
312 // complete our taxonomy and add rewrite rules filters once custom post types and taxonomies are registered (normally in init)
313 function prepare_rewrite_rules() {
314 foreach ($this->post_types as $post_type)
315 register_taxonomy_for_object_type('language', $post_type);
316
317 // don't modify the rules if there is no languages created yet
318 if (!$this->get_languages_list())
319 return;
320
321 $types = array_merge(array('post', 'date', 'root', 'comments', 'search', 'author', 'page'), array_keys($GLOBALS['wp_rewrite']->extra_permastructs));
322 $types = apply_filters('pll_rewrite_rules', $types); // allow plugins to add rewrite rules to the language filter
323 foreach ($types as $type)
324 add_filter($type . '_rewrite_rules', array(&$this, 'rewrite_rules'));
325
326 add_filter('rewrite_rules_array', array(&$this, 'rewrite_rules')); // needed for post type archives
327 }
328
329 // the rewrite rules !
330 // always make sure the default language is at the end in case the language information is hidden for default language
331 // thanks to brbrbr http://wordpress.org/support/topic/plugin-polylang-rewrite-rules-not-correct
332 function rewrite_rules($rules) {
333
334 // suppress the rules created by WordPress for our taxonomy
335 if (($current_filter = current_filter()) == 'language_rewrite_rules')
336 return array();
337
338 $options = get_option('polylang');
339 $to_rewrite = array('date_rewrite_rules', 'root_rewrite_rules', 'comments_rewrite_rules', 'author_rewrite_rule', 'post_format_rewrite_rules');
340 $newrules = array();
341
342 foreach ($this->get_languages_list() as $language)
343 if (!$options['hide_default'] || $options['default_lang'] != $language->slug)
344 $languages[] = $language->slug;
345
346 if (isset($languages))
347 $slug = $options['rewrite'] ? '('.implode('|', $languages).')/' : 'language/('.implode('|', $languages).')/';
348
349 foreach ($rules as $key => $rule) {
350 // special case for pages which do not accept adding the lang parameter
351 if ($current_filter == 'page_rewrite_rules' && $options['force_lang']) {
352 if (isset($slug))
353 $newrules[$slug.$key] = str_replace(array('[4]', '[3]', '[2]', '[1]'), array('[5]', '[4]', '[3]', '[2]'), $rule); // hopefully it is sufficient !
354
355 if ($options['hide_default'])
356 $newrules[$key] = $rules[$key];
357
358 unset($rules[$key]); // now useless
359 }
360
361 // rewrite rules filtered by language
362 elseif (in_array($current_filter, $to_rewrite) || strpos($rule, 'post_type=') || ($current_filter != 'rewrite_rules_array' && $options['force_lang'])) {
363 if (isset($slug))
364 $newrules[$slug.$key] = str_replace(array('[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?'),
365 array('[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&'), $rule); // hopefully it is sufficient !
366
367 if ($options['hide_default'])
368 $newrules[$key] = str_replace('?', '?lang='.$options['default_lang'].'&', $rule);
369
370 unset($rules[$key]); // now useless
371 }
372 }
373
374 // the home rewrite rule
375 if ($current_filter == 'root_rewrite_rules' && isset($slug))
376 $newrules[$slug.'?$'] = 'index.php?lang=$matches[1]';
377
378 return $newrules + $rules;
379 }
380
381 } // class Polylang
382
383 if (class_exists("Polylang"))
384 new Polylang();
385 ?>
386