PluginProbe
Polylang / 3.3
Polylang v3.3
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 / include / links-directory.php

links-directory.php in Polylang 3.3, at include/links-directory.php

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