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

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