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

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