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

359 lines 13.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://wordpress.org/extend/plugins/polylang/
5 Version: 0.7
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, version 2, as
14 published by the Free Software Foundation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26 define('POLYLANG_VERSION', '0.7');
27 define('PLL_MIN_WP_VERSION', '3.1');
28
29 define('POLYLANG_DIR', dirname(__FILE__)); // our directory
30 define('PLL_INC', POLYLANG_DIR.'/include');
31
32 define('POLYLANG_URL', WP_PLUGIN_URL.'/'.basename(POLYLANG_DIR)); // our url
33
34 if (!defined('PLL_LOCAL_DIR'))
35 define('PLL_LOCAL_DIR', WP_CONTENT_DIR.'/polylang'); // default directory to store user data such as custom flags
36
37 if (!defined('PLL_LOCAL_URL'))
38 define('PLL_LOCAL_URL', WP_CONTENT_URL.'/polylang'); // default url to access user data such as custom flags
39
40 if (!defined('PLL_DISPLAY_ALL'))
41 define('PLL_DISPLAY_ALL', false); // diplaying posts & terms with undefined language is disabled by default
42
43 require_once(PLL_INC.'/base.php');
44 require_once(PLL_INC.'/widget.php');
45 require_once(PLL_INC.'/calendar.php');
46
47 // controls the plugin, deals with activation, deactivation, upgrades, initialization as well as rewrite rules
48 class Polylang extends Polylang_Base {
49
50 function __construct() {
51 global $polylang; // globalize the variable to access it in the API
52
53 // manages plugin activation and deactivation
54 register_activation_hook( __FILE__, array(&$this, 'activate') );
55 register_deactivation_hook( __FILE__, array(&$this, 'deactivate') );
56
57 // stopping here if we are going to deactivate the plugin avoids breaking rewrite rules
58 if (isset($_GET['action']) && $_GET['action'] == 'deactivate' && isset($_GET['plugin']) && $_GET['plugin'] == 'polylang/polylang.php')
59 return;
60
61 // manages plugin upgrade
62 add_filter('upgrader_post_install', array(&$this, 'post_upgrade'));
63 add_action('admin_init', array(&$this, 'admin_init'));
64
65 // plugin and widget initialization
66 add_action('init', array(&$this, 'init'));
67 add_action('widgets_init', array(&$this, 'widgets_init'));
68
69 // rewrite rules
70 add_filter('rewrite_rules_array', array(&$this, 'rewrite_rules_array' ));
71
72 // separate admin and frontend
73 if (is_admin()) {
74 require_once(PLL_INC.'/admin.php');
75 $polylang = new Polylang_Admin();
76 }
77 else {
78 require_once(PLL_INC.'/core.php');
79 $polylang = new Polylang_Core();
80 }
81
82 // loads the API
83 require_once(PLL_INC.'/api.php');
84 }
85
86 // plugin activation for multisite
87 function activate() {
88 global $wp_version, $wpdb;
89
90 if (version_compare($wp_version, PLL_MIN_WP_VERSION , '<'))
91 die (sprintf('<p style = "font-family: sans-serif; font-size: 12px; color: #333; margin: -5px">%s</p>',
92 sprintf(__('You are using WordPress %s. Polylang requires at least WordPress %s.', 'polylang'), $wp_version, PLL_MIN_WP_VERSION)));
93
94 // check if it is a network activation - if so, run the activation function for each blog
95 if (is_multisite() && isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
96 foreach ($wpdb->get_col($wpdb->prepare("SELECT blog_id FROM $wpdb->blogs")) as $blog_id) {
97 switch_to_blog($blog_id);
98 $this->_activate();
99 }
100 restore_current_blog();
101 }
102 else
103 $this->_activate();
104 }
105
106 // plugin activation
107 function _activate() {
108 // create the termmeta table - not provided by WP by default - if it does not already exists
109 // uses exactly the same model as other meta tables to be able to use access functions provided by WP
110 global $wpdb;
111 $charset_collate = '';
112 if ( ! empty($wpdb->charset) )
113 $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
114 if ( ! empty($wpdb->collate) )
115 $charset_collate .= " COLLATE $wpdb->collate";
116
117 $table = $wpdb->prefix . 'termmeta';
118
119 $wpdb->query("CREATE TABLE IF NOT EXISTS $table (
120 meta_id bigint(20) unsigned NOT NULL auto_increment,
121 term_id bigint(20) unsigned NOT NULL default '0',
122 meta_key varchar(255) default NULL,
123 meta_value longtext,
124 PRIMARY KEY (meta_id),
125 KEY term_id (term_id),
126 KEY meta_key (meta_key)
127 ) $charset_collate;");
128
129 // codex tells to use the init action to call register_taxonomy but I need it now for my rewrite rules
130 register_taxonomy('language', get_post_types(array('show_ui' => true)), array('label' => false, 'query_var'=>'lang'));
131
132 // defines default values for options in case this is the first installation
133 $options = get_option('polylang');
134 if (!$options) {
135 $options['browser'] = 1; // default language for the front page is set by browser preference
136 $options['rewrite'] = 0; // do not remove /language/ in permalinks
137 $options['hide_default'] = 0; // do not remove URL language information for default language
138 $options['force_lang'] = 0; // do not add URL language information when useless
139 }
140 $options['version'] = POLYLANG_VERSION;
141 update_option('polylang', $options);
142
143 // add our rewrite rules
144 global $wp_rewrite;
145 $wp_rewrite->flush_rules();
146 }
147
148 // plugin deactivation for multisite
149 function deactivate() {
150 global $wpdb;
151
152 // check if it is a network deactivation - if so, run the deactivation function for each blog
153 if (is_multisite() && isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
154 foreach ($wpdb->get_col($wpdb->prepare("SELECT blog_id FROM $wpdb->blogs")) as $blog_id) {
155 switch_to_blog($blog_id);
156 $this->_deactivate();
157 }
158 restore_current_blog();
159 }
160 else
161 $this->_deactivate();
162 }
163
164 // plugin deactivation
165 function _deactivate() {
166 global $wp_rewrite;
167 $wp_rewrite->flush_rules();
168 }
169
170 // restores the local_flags directory after upgrade from version 0.5.1 or older
171 function post_upgrade() {
172 // nothing to restore
173 if (!@is_dir($upgrade_dir = WP_CONTENT_DIR . '/upgrade/polylang/local_flags'))
174 return true;
175
176 // don't move if the directory is empty
177 $contents = @scandir($upgrade_dir);
178 if (is_array($contents) && ($files = array_diff($contents, array(".", "..", ".DS_Store", "_notes", "Thumbs.db"))) && empty($files))
179 return true;
180
181 // move the directory to wp-content
182 if (!@rename($upgrade_dir, PLL_LOCAL_DIR))
183 return new WP_Error('polylang_restore_error', sprintf('%s<br />%s',
184 __('Error: Restore of local flags failed!', 'polylang'),
185 sprintf(__('Please move your local flags from %s to %s', 'polylang'), esc_html($upgrade_dir), '<strong>'.esc_html(PLL_LOCAL_DIR).'</strong>')
186 ));
187
188 @rmdir(WP_CONTENT_DIR . '/upgrade/polylang');
189 return true;
190 }
191
192 // upgrades from old translation used up to V0.4.4 to new model used in V0.5+
193 function upgrade_translations($type, $ids) {
194 $listlanguages = $this->get_languages_list();
195 foreach ($ids as $id) {
196 $lang = call_user_func(array(&$this, 'get_'.$type.'_language'), $id);
197 if (!$lang)
198 continue;
199
200 $tr = array();
201 foreach ($listlanguages as $language) {
202 if ($meta = get_metadata($type, $id, '_lang-'.$language->slug, true))
203 $tr[$language->slug] = $meta;
204 }
205
206 if(!empty($tr)) {
207 $tr = serialize(array_merge(array($lang->slug => $id), $tr));
208 update_metadata($type, $id, '_translations', $tr);
209 }
210 }
211 }
212
213 // manage upgrade even when it is done manually
214 function admin_init() {
215 $options = get_option('polylang');
216 if (version_compare($options['version'], POLYLANG_VERSION, '<')) {
217
218 if (version_compare($options['version'], '0.4', '<'))
219 $options['hide_default'] = 0; // option introduced in 0.4
220
221 // translation model changed in V0.5
222 if (version_compare($options['version'], '0.5', '<')) {
223 $ids = get_posts(array('numberposts'=>-1, 'fields' => 'ids', 'post_type'=>'any', 'post_status'=>'any'));
224 $this->upgrade_translations('post', $ids);
225 $ids = get_terms(get_taxonomies(array('show_ui'=>true)), array('get'=>'all', 'fields'=>'ids'));
226 $this->upgrade_translations('term', $ids);
227 }
228
229 // translation model changed in V0.5
230 // deleting the old one has been delayed in V0.6 (just in case...)
231 if (version_compare($options['version'], '0.6', '<')) {
232 $listlanguages = $this->get_languages_list();
233
234 $ids = get_posts(array('numberposts'=> -1, 'fields' => 'ids', 'post_type'=>'any', 'post_status'=>'any'));
235 foreach ($ids as $id) {
236 foreach ($listlanguages as $lang)
237 delete_post_meta($id, '_lang-'.$lang->slug);
238 }
239
240 $ids = get_terms(get_taxonomies(array('show_ui'=>true)), array('get'=>'all', 'fields'=>'ids'));
241 foreach ($ids as $id) {
242 foreach ($listlanguages as $lang)
243 delete_metadata('term', $id, '_lang-'.$lang->slug);
244 }
245 }
246
247 if (version_compare($options['version'], '0.7', '<'))
248 $options['force_lang'] = 0; // option introduced in 0.7
249
250 $options['version'] = POLYLANG_VERSION;
251 update_option('polylang', $options);
252 }
253 }
254
255 // some initialization
256 function init() {
257 global $wpdb;
258 $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb
259
260 // registers the language taxonomy
261 // codex: use the init action to call this function
262 register_taxonomy('language', get_post_types(array('show_ui' => true)), array(
263 'label' => false,
264 'public' => false, // avoid displaying the 'like post tags text box' in the quick edit
265 'query_var'=>'lang',
266 'update_count_callback' => '_update_post_term_count'));
267
268 // optionaly removes 'language' in permalinks so that we get http://www.myblog/en/ instead of http://www.myblog/language/en/
269 // the simple line of code is inspired by the WP No Category Base plugin: http://wordpresssupplies.com/wordpress-plugins/no-category-base/
270 global $wp_rewrite;
271 $options = get_option('polylang');
272 if ($options['rewrite'] && $wp_rewrite->extra_permastructs)
273 $wp_rewrite->extra_permastructs['language'][0] = '%language%';
274
275 load_plugin_textdomain('polylang', false, basename(POLYLANG_DIR).'/languages'); // plugin i18n
276 }
277
278 // registers our widgets
279 function widgets_init() {
280 register_widget('Polylang_Widget');
281
282 // overwrites the calendar widget to filter posts by language
283 unregister_widget('WP_Widget_Calendar');
284 register_widget('Polylang_Widget_Calendar');
285 }
286
287 // rewrites rules if pretty permalinks are used
288 function rewrite_rules_array($rules) {
289 $options = get_option('polylang');
290 $newrules = array();
291
292 // don't modify the rules if there is no languages created
293 if (!($listlanguages = $this->get_languages_list()))
294 return $rules;
295
296 // modifies the rules created by WordPress when '/language/' is removed in permalinks
297 if ($options['rewrite']) {
298 foreach ($listlanguages as $language) {
299 $slug = $options['default_lang'] == $language->slug && $options['hide_default'] ? '' : $language->slug . '/';
300 $newrules[$slug.'feed/(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]';
301 $newrules[$slug.'(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]';
302 $newrules[$slug.'page/?([0-9]{1,})/?$'] = 'index.php?lang='.$language->slug.'&paged=$matches[1]';
303 if ($slug)
304 $newrules[$slug.'?$'] = 'index.php?lang='.$language->slug;
305 }
306 unset($rules['([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?lang=$matches[1]&feed=$matches[2]
307 unset($rules['([^/]+)/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?lang=$matches[1]&feed=$matches[2]
308 unset($rules['([^/]+)/page/?([0-9]{1,})/?$']); // => index.php?lang=$matches[1]&paged=$matches[2]
309 unset($rules['([^/]+)/?$']); // => index.php?lang=$matches[1]
310 }
311
312 $base = $options['rewrite'] ? '' : 'language/';
313
314 // rewrite rules for comments feed filtered by language
315 foreach ($listlanguages as $language) {
316 $slug = $options['default_lang'] == $language->slug && $options['hide_default'] ? '' : $base.$language->slug . '/';
317 $newrules[$slug.'comments/feed/(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]&withcomments=1';
318 $newrules[$slug.'comments/(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]&withcomments=1';
319 }
320 unset($rules['comments/feed/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?&feed=$matches[1]&withcomments=1
321 unset($rules['comments/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?&feed=$matches[1]&withcomments=1
322
323 // rewrite rules for archives filtered by language
324 foreach ($rules as $key => $rule) {
325 $is_archive = strpos($rule, 'post_format=') || strpos($rule, 'author_name=') || strpos($rule, 'post_type=') || strpos($rule, 'year=') && !(
326 strpos($rule, 'p=') ||
327 strpos($rule, 'name=') ||
328 strpos($rule, 'page=') ||
329 strpos($rule, 'cpage=') );
330
331 if ($is_archive) {
332 foreach ($listlanguages as $language) {
333 $slug = $options['default_lang'] == $language->slug && $options['hide_default'] ? '' : $base.$language->slug . '/';
334 $newrules[$slug.$key] = str_replace('?', '?lang='.$language->slug.'&', $rule);
335 }
336 unset($rules[$key]); // now useless
337 }
338 }
339
340 // optionally add the language information to all urls
341 if ($options['force_lang']) {
342 foreach ($rules as $key => $rule) {
343 foreach ($listlanguages as $language) {
344 $slug = $options['default_lang'] == $language->slug && $options['hide_default'] ? '' : $base.$language->slug . '/';
345 $newrules[$slug.$key] = $rules[$key];
346 }
347 unset($rules[$key]); // now useless
348 }
349 }
350
351 return $newrules + $rules;
352 }
353
354 } // class Polylang
355
356 if (class_exists("Polylang"))
357 new Polylang();
358 ?>
359