PluginProbe
Polylang / 1.5
Polylang v1.5
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
← All changes | include/links-directory.php +123 -184 3.01.5 View file →
@@ -1,88 +1,62 @@
1 1 <?php
2 -/**
3 - * @package Polylang
4 - */
5 2
6 -/**
7 - * Links model for use when the language code is added in url as a directory
3 +/*
4 + * links model for use when the language code is added in url as a directory
8 5 * for example mysite.com/en/something
9 6 * implements the "links_model interface"
10 7 *
11 8 * @since 1.2
12 9 */
13 -class PLL_Links_Directory extends PLL_Links_Permalinks {
14 - /**
15 - * Relative path to the home url.
16 - *
17 - * @var string
18 - */
19 - protected $home_relative;
10 +class PLL_Links_Directory extends PLL_Links_Model {
11 + protected $index = 'index.php'; // need this before $wp_rewrite is created, also harcoded in wp-includes/rewrite.php
12 + protected $root;
13 + protected $rewrite_rules = array();
14 + protected $always_rewrite = array('date', 'root', 'comments', 'search', 'author', 'post_format', 'language');
20 15
21 - /**
22 - * Constructor.
16 + /*
17 + * constructor
23 18 *
24 19 * @since 1.2
25 20 *
26 - * @param PLL_Model $model PLL_Model instance.
21 + * @param object $model PLL_Model instance
27 22 */
28 - public function __construct( &$model ) {
29 - parent::__construct( $model );
23 + public function __construct(&$model) {
24 + parent::__construct($model);
30 25
31 - $this->home_relative = home_url( '/', 'relative' );
26 + // inspired by wp-includes/rewrite.php
27 + $this->root = preg_match('#^/*' . $this->index . '#', get_option('permalink_structure')) ? $this->index . '/' : '';
32 28
33 - if ( did_action( 'pll_init' ) ) {
34 - $this->init();
35 - } else {
36 - add_action( 'pll_init', array( $this, 'init' ) );
37 - }
38 - }
29 + add_action ('setup_theme', array(&$this, 'add_permastruct'));
39 30
40 - /**
41 - * Called only at first object creation to avoid duplicating filters when switching blog
42 - *
43 - * @since 1.6
44 - *
45 - * @return void
46 - */
47 - public function init() {
48 - if ( did_action( 'setup_theme' ) ) {
49 - $this->add_permastruct();
50 - } else {
51 - add_action( 'setup_theme', array( $this, 'add_permastruct' ), 2 );
52 - }
31 + // refresh rewrite rules if the 'page_on_front' option is modified
32 + add_action('update_option_page_on_front', 'flush_rewrite_rules');
53 33
54 - // Make sure to prepare rewrite rules when flushing
55 - add_action( 'pre_option_rewrite_rules', array( $this, 'prepare_rewrite_rules' ) );
34 + // make sure to prepare rewrite rules when flushing
35 + add_action ('pre_option_rewrite_rules', array(&$this, 'prepare_rewrite_rules'));
56 36 }
57 37
58 - /**
59 - * Adds the language code in a url.
60 - * links_model interface.
38 + /*
39 + * adds the language code in url
40 + * links_model interface
61 41 *
62 42 * @since 1.2
63 43 *
64 - * @param string $url The url to modify.
65 - * @param PLL_Language $lang The language object.
66 - * @return string Modified url.
44 + * @param string $url url to modify
45 + * @param object $lang language
46 + * @return string modified url
67 47 */
68 - public function add_language_to_link( $url, $lang ) {
69 - if ( ! empty( $lang ) ) {
48 + public function add_language_to_link($url, $lang) {
49 + if (!empty($lang)) {
70 50 $base = $this->options['rewrite'] ? '' : 'language/';
71 51 $slug = $this->options['default_lang'] == $lang->slug && $this->options['hide_default'] ? '' : $base . $lang->slug . '/';
72 - $root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : preg_replace( '#^https?://#', '://', $this->home . '/' . $this->root );
73 -
74 - if ( false === strpos( $url, $new = $root . $slug ) ) {
75 - $pattern = preg_quote( $root, '#' );
76 - $pattern = '#' . $pattern . '#';
77 - return preg_replace( $pattern, $new, $url, 1 ); // Only once
78 - }
52 + return str_replace($this->home . '/' . $this->root, $this->home . '/' . $this->root . $slug, $url);
79 53 }
80 54 return $url;
81 55 }
82 56
83 - /**
84 - * Returns the url without language code
57 + /*
58 + * returns the url without language code
85 59 * links_model interface
86 60 *
87 61 * @since 1.2
88 62 *
@@ -88,191 +62,156 @@
88 62 *
89 63 * @param string $url url to modify
90 64 * @return string modified url
91 65 */
92 - public function remove_language_from_link( $url ) {
93 - $languages = array();
94 -
95 - foreach ( $this->model->get_languages_list() as $language ) {
96 - if ( ! $this->options['hide_default'] || $this->options['default_lang'] != $language->slug ) {
66 + function remove_language_from_link($url) {
67 + foreach ($this->model->get_languages_list() as $language)
68 + if (!$this->options['hide_default'] || $this->options['default_lang'] != $language->slug)
97 69 $languages[] = $language->slug;
98 - }
99 - }
100 70
101 - if ( ! empty( $languages ) ) {
102 - $root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : preg_replace( '#^https?://#', '://', $this->home . '/' . $this->root );
103 -
104 - $pattern = preg_quote( $root, '#' );
105 - $pattern = '#' . $pattern . ( $this->options['rewrite'] ? '' : 'language/' ) . '(' . implode( '|', $languages ) . ')(/|$)#';
106 - $url = preg_replace( $pattern, $root, $url );
71 + if (!empty($languages)) {
72 + $pattern = str_replace('/', '\/', $this->home . '/' . $this->root);
73 + $pattern = '#' . $pattern . ($this->options['rewrite'] ? '' : 'language') . '('.implode('|', $languages).')(\/|$)#';
74 + $url = preg_replace($pattern, $this->home . '/' . $this->root, $url);
107 75 }
108 76 return $url;
109 77 }
110 78
111 - /**
112 - * Returns the language based on language code in url
79 + /*
80 + * returns the language based on language code in url
113 81 * links_model interface
114 82 *
115 83 * @since 1.2
116 - * @since 2.0 add $url argument
117 84 *
118 - * @param string $url optional, defaults to current url
119 85 * @return string language slug
120 86 */
121 - public function get_language_from_url( $url = '' ) {
122 - if ( empty( $url ) ) {
123 - $url = pll_get_requested_url();
124 - }
125 -
126 - $path = wp_parse_url( $url, PHP_URL_PATH );
127 - $root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : $this->home . '/' . $this->root;
128 -
129 - $pattern = wp_parse_url( $root . ( $this->options['rewrite'] ? '' : 'language/' ), PHP_URL_PATH );
130 - $pattern = preg_quote( $pattern, '#' );
131 - $pattern = '#^' . $pattern . '(' . implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')(/|$)#';
132 - return preg_match( $pattern, trailingslashit( $path ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
87 + public function get_language_from_url() {
88 + $requested_url = (is_ssl() ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
89 + $pattern = str_replace('/', '\/', $this->home . '/' . $this->root . ($this->options['rewrite'] ? '' : 'language/'));
90 + $pattern = '#' . $pattern . '('. implode('|', $this->model->get_languages_list(array('fields' => 'slug'))) . ')(\/|$)#';
91 + return preg_match($pattern, trailingslashit($requested_url), $matches) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
133 92 }
134 93
135 - /**
136 - * Returns the home url in a given language.
137 - * links_model interface.
94 + /*
95 + * returns the home url
96 + * links_model interface
138 97 *
139 98 * @since 1.3.1
140 99 *
141 - * @param PLL_Language $lang PLL_Language object.
100 + * @param object $lang PLL_Language object
142 101 * @return string
143 102 */
144 - public function home_url( $lang ) {
145 - $base = $this->options['rewrite'] ? '' : 'language/';
146 - $slug = $this->options['default_lang'] == $lang->slug && $this->options['hide_default'] ? '' : '/' . $this->root . $base . $lang->slug;
147 - return trailingslashit( $this->home . $slug );
103 + public function home_url($lang) {
104 + return $this->options['hide_default'] && $lang->slug == $this->options['default_lang'] ? $this->home : get_term_link($lang, 'language');
148 105 }
149 106
150 - /**
151 - * Optionally removes 'language' in permalinks so that we get http://www.myblog/en/ instead of http://www.myblog/language/en/
107 + /*
108 + * optionaly removes 'language' in permalinks so that we get http://www.myblog/en/ instead of http://www.myblog/language/en/
152 109 *
153 110 * @since 1.2
154 - *
155 - * @return void
156 111 */
157 - public function add_permastruct() {
158 - // Language information always in front of the uri ( 'with_front' => false )
159 - // The 3rd parameter structure has been modified in WP 3.4
160 - // Leads to error 404 for pages when there is no language created yet
161 - if ( $this->model->get_languages_list() ) {
162 - add_permastruct( 'language', $this->options['rewrite'] ? '%language%' : 'language/%language%', array( 'with_front' => false ) );
163 - }
112 + function add_permastruct() {
113 + // language information always in front of the uri ('with_front' => false)
114 + // the 3rd parameter structure has been modified in WP 3.4
115 + add_permastruct('language', $this->options['rewrite'] ? '%language%' : 'language/%language%', array('with_front' => false));
164 116 }
165 117
166 - /**
167 - * Prepares the rewrite rules filters.
118 + /*
119 + * prepares rewrite rules filters
168 120 *
169 121 * @since 0.8.1
170 122 *
171 - * @param mixed $pre Not used as the filter is used as an action.
172 - * @return mixed
123 + * @param array $pre not used
124 + * @return unmodified $pre
173 125 */
174 - public function prepare_rewrite_rules( $pre ) {
175 - // Don't modify the rules if there is no languages created yet
176 - // Make sure to add filter only once and if all custom post types and taxonomies have been registered
177 - if ( $this->model->get_languages_list() && did_action( 'wp_loaded' ) && ! has_filter( 'language_rewrite_rules', '__return_empty_array' ) ) {
178 - // Suppress the rules created by WordPress for our taxonomy
179 - add_filter( 'language_rewrite_rules', '__return_empty_array' );
126 + public function prepare_rewrite_rules($pre) {
127 + //clean filters which could have been set in a previous call (may occur when changing Polylang settings)
128 + foreach ($this->rewrite_rules as $type)
129 + remove_filter($type . '_rewrite_rules', array(&$this, 'rewrite_rules'));
180 130
181 - foreach ( $this->get_rewrite_rules_filters() as $type ) {
182 - add_filter( $type . '_rewrite_rules', array( $this, 'rewrite_rules' ) );
183 - }
131 + // don't modify the rules if there is no languages created yet
132 + if ($this->model->get_languages_list()) {
133 + // make sure we have the right post types and taxonomies
134 + $types = array_values(array_merge($this->model->get_translated_post_types(), $this->model->get_translated_taxonomies()));
135 + $types = array_merge($this->always_rewrite, $types);
136 + $this->rewrite_rules = apply_filters('pll_rewrite_rules', $types); // allow plugins to add rewrite rules to the language filter
184 137
185 - add_filter( 'rewrite_rules_array', array( $this, 'rewrite_rules' ) ); // needed for post type archives
138 + foreach ($this->rewrite_rules as $type)
139 + add_filter($type . '_rewrite_rules', array(&$this, 'rewrite_rules'));
140 +
141 + add_filter('rewrite_rules_array', array(&$this, 'rewrite_rules')); // needed for post type archives
186 142 }
187 143 return $pre;
188 144 }
189 145
190 - /**
191 - * The rewrite rules !
192 - * Always make sure that the default language is at the end in case the language information is hidden for default language.
193 - * Thanks to brbrbr http://wordpress.org/support/topic/plugin-polylang-rewrite-rules-not-correct.
146 + /*
147 + * the rewrite rules !
148 + * always make sure the default language is at the end in case the language information is hidden for default language
149 + * thanks to brbrbr http://wordpress.org/support/topic/plugin-polylang-rewrite-rules-not-correct
194 150 *
195 151 * @since 0.8.1
196 152 *
197 - * @param string[] $rules Rewrite rules.
198 - * @return string[] Modified rewrite rules.
153 + * @param array $rules rewrite rules
154 + * @return array modified rewrite rules
199 155 */
200 - public function rewrite_rules( $rules ) {
201 - $filter = str_replace( '_rewrite_rules', '', current_filter() );
156 + public function rewrite_rules($rules) {
157 + $filter = str_replace('_rewrite_rules', '', current_filter());
202 158
159 + // suppress the rules created by WordPress for our taxonomy
160 + if ($filter == 'language')
161 + return array();
162 +
203 163 global $wp_rewrite;
204 164 $newrules = array();
205 165
206 - $languages = $this->model->get_languages_list( array( 'fields' => 'slug' ) );
207 - if ( $this->options['hide_default'] ) {
208 - $languages = array_diff( $languages, array( $this->options['default_lang'] ) );
209 - }
166 + $languages = $this->model->get_languages_list(array('fields' => 'slug'));
167 + if ($this->options['hide_default'])
168 + $languages = array_diff($languages, array($this->options['default_lang']));
210 169
211 - if ( ! empty( $languages ) ) {
212 - $slug = $wp_rewrite->root . ( $this->options['rewrite'] ? '' : 'language/' ) . '(' . implode( '|', $languages ) . ')/';
213 - }
170 + if (!empty($languages))
171 + $slug = $wp_rewrite->root . ($this->options['rewrite'] ? '' : 'language/') . '('.implode('|', $languages).')/';
214 172
215 - // For custom post type archives
216 - $cpts = array_intersect( $this->model->get_translated_post_types(), get_post_types( array( '_builtin' => false ) ) );
217 - $cpts = $cpts ? '#post_type=(' . implode( '|', $cpts ) . ')#' : '';
173 + // for custom post type archives
174 + $cpts = array_intersect($this->model->get_translated_post_types(), get_post_types(array('_builtin' => false)));
175 + $cpts = $cpts ? '#post_type=('.implode('|', $cpts).')#' : '';
218 176
219 - foreach ( $rules as $key => $rule ) {
220 - // Special case for translated post types and taxonomies to allow canonical redirection
221 - if ( $this->options['force_lang'] && in_array( $filter, array_merge( $this->model->get_translated_post_types(), $this->model->get_translated_taxonomies() ) ) ) {
177 + foreach ($rules as $key => $rule) {
178 + // we don't need the lang parameter for post types and taxonomies
179 + // moreover adding it would create issues for pages and taxonomies
180 + if ($this->options['force_lang'] && in_array($filter, array_merge($this->model->get_translated_post_types(), $this->model->get_translated_taxonomies()))) {
181 + if (isset($slug))
182 + $newrules[$slug.str_replace($wp_rewrite->root, '', $key)] = str_replace(
183 + array('[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]'),
184 + array('[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]'),
185 + $rule
186 + ); // hopefully it is sufficient!
222 187
223 - /**
224 - * Filters the rewrite rules to modify
225 - *
226 - * @since 1.9.1
227 - *
228 - * @param bool $modify whether to modify or not the rule, defaults to true
229 - * @param array $rule original rewrite rule
230 - * @param string $filter current set of rules being modified
231 - * @param string|bool $archive custom post post type archive name or false if it is not a cpt archive
232 - */
233 - if ( isset( $slug ) && apply_filters( 'pll_modify_rewrite_rule', true, array( $key => $rule ), $filter, false ) ) {
234 - $newrules[ $slug . str_replace( $wp_rewrite->root, '', ltrim( $key, '^' ) ) ] = str_replace(
235 - array( '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?' ),
236 - array( '[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&' ),
237 - $rule
238 - ); // Should be enough!
188 + if ($this->options['hide_default']) {
189 + $newrules[$key] = $rules[$key];
190 + // unset only if we hide the code for the default language as check_language_code_in_url will do its job in other cases
191 + unset($rules[$key]);
239 192 }
240 -
241 - $newrules[ $key ] = $rule;
242 193 }
243 194
244 - // Rewrite rules filtered by language
245 - elseif ( in_array( $filter, $this->always_rewrite ) || in_array( $filter, $this->model->get_filtered_taxonomies() ) || ( $cpts && preg_match( $cpts, $rule, $matches ) && ! strpos( $rule, 'name=' ) ) || ( 'rewrite_rules_array' != $filter && $this->options['force_lang'] ) ) {
195 + // rewrite rules filtered by language
196 + elseif (in_array($filter, $this->always_rewrite) || ($cpts && preg_match($cpts, $rule) && !strpos($rule, 'name=')) || ($filter != 'rewrite_rules_array' && $this->options['force_lang'])) {
197 + if (isset($slug))
198 + $newrules[$slug.str_replace($wp_rewrite->root, '', $key)] = str_replace(
199 + array('[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?'),
200 + array('[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&'),
201 + $rule
202 + ); // should be enough!
246 203
247 - /** This filter is documented in include/links-directory.php */
248 - if ( apply_filters( 'pll_modify_rewrite_rule', true, array( $key => $rule ), $filter, empty( $matches[1] ) ? false : $matches[1] ) ) {
249 - if ( isset( $slug ) ) {
250 - $newrules[ $slug . str_replace( $wp_rewrite->root, '', ltrim( $key, '^' ) ) ] = str_replace(
251 - array( '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?' ),
252 - array( '[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&' ),
253 - $rule
254 - ); // Should be enough!
255 - }
204 + if ($this->options['hide_default'])
205 + $newrules[$key] = str_replace('?', '?lang='.$this->options['default_lang'].'&', $rule);
256 206
257 - if ( $this->options['hide_default'] ) {
258 - $newrules[ $key ] = str_replace( '?', '?lang=' . $this->options['default_lang'] . '&', $rule );
259 - }
260 - } else {
261 - $newrules[ $key ] = $rule;
262 - }
207 + unset($rules[$key]); // now useless
263 208 }
264 -
265 - // Unmodified rules
266 - else {
267 - $newrules[ $key ] = $rule;
268 - }
269 209 }
270 210
271 - // The home rewrite rule
272 - if ( 'root' == $filter && isset( $slug ) ) {
273 - $newrules[ $slug . '?$' ] = $wp_rewrite->index . '?lang=$matches[1]';
274 - }
211 + // the home rewrite rule
212 + if ($filter == 'root' && isset($slug))
213 + $newrules[$slug.'?$'] = $wp_rewrite->index.'?lang=$matches[1]';
275 214
276 - return $newrules;
215 + return $newrules + $rules;
277 216 }
278 217 }