PluginProbe
Polylang / 2.8.3
Polylang v2.8.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 2.8.3, at include/links-directory.php

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