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

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