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

266 lines 9.0 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 : $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 : $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 $path = $_SERVER['REQUEST_URI'];
112 } else {
113 $path = parse_url( $url, PHP_URL_PATH );
114 }
115
116 $root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : $this->home . '/' . $this->root;
117
118 $pattern = parse_url( $root . ( $this->options['rewrite'] ? '' : 'language/' ), PHP_URL_PATH );
119 $pattern = str_replace( '/', '\/', $pattern );
120 $pattern = '#' . $pattern . '(' . implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')(\/|$)#';
121 return preg_match( $pattern, trailingslashit( $path ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
122 }
123
124 /**
125 * Returns the home url
126 * links_model interface
127 *
128 * @since 1.3.1
129 *
130 * @param object $lang PLL_Language object
131 * @return string
132 */
133 public function home_url( $lang ) {
134 $base = $this->options['rewrite'] ? '' : 'language/';
135 $slug = $this->options['default_lang'] == $lang->slug && $this->options['hide_default'] ? '' : '/' . $this->root . $base . $lang->slug;
136 return trailingslashit( $this->home . $slug );
137 }
138
139 /**
140 * Optionally removes 'language' in permalinks so that we get http://www.myblog/en/ instead of http://www.myblog/language/en/
141 *
142 * @since 1.2
143 */
144 public function add_permastruct() {
145 // Language information always in front of the uri ( 'with_front' => false )
146 // The 3rd parameter structure has been modified in WP 3.4
147 // Leads to error 404 for pages when there is no language created yet
148 if ( $this->model->get_languages_list() ) {
149 add_permastruct( 'language', $this->options['rewrite'] ? '%language%' : 'language/%language%', array( 'with_front' => false ) );
150 }
151 }
152
153 /**
154 * Prepares rewrite rules filters
155 *
156 * @since 0.8.1
157 *
158 * @param array $pre not used
159 * @return unmodified $pre
160 */
161 public function prepare_rewrite_rules( $pre ) {
162 // Don't modify the rules if there is no languages created yet
163 // Make sure to add filter only once and if all custom post types and taxonomies have been registered
164 if ( $this->model->get_languages_list() && did_action( 'wp_loaded' ) && ! has_filter( 'language_rewrite_rules', '__return_empty_array' ) ) {
165 // Suppress the rules created by WordPress for our taxonomy
166 add_filter( 'language_rewrite_rules', '__return_empty_array' );
167
168 foreach ( $this->get_rewrite_rules_filters() as $type ) {
169 add_filter( $type . '_rewrite_rules', array( $this, 'rewrite_rules' ) );
170 }
171
172 add_filter( 'rewrite_rules_array', array( $this, 'rewrite_rules' ) ); // needed for post type archives
173 }
174 return $pre;
175 }
176
177 /**
178 * The rewrite rules !
179 * always make sure the default language is at the end in case the language information is hidden for default language
180 * thanks to brbrbr http://wordpress.org/support/topic/plugin-polylang-rewrite-rules-not-correct
181 *
182 * @since 0.8.1
183 *
184 * @param array $rules rewrite rules
185 * @return array modified rewrite rules
186 */
187 public function rewrite_rules( $rules ) {
188 $filter = str_replace( '_rewrite_rules', '', current_filter() );
189
190 global $wp_rewrite;
191 $newrules = array();
192
193 $languages = $this->model->get_languages_list( array( 'fields' => 'slug' ) );
194 if ( $this->options['hide_default'] ) {
195 $languages = array_diff( $languages, array( $this->options['default_lang'] ) );
196 }
197
198 if ( ! empty( $languages ) ) {
199 $slug = $wp_rewrite->root . ( $this->options['rewrite'] ? '' : 'language/' ) . '(' . implode( '|', $languages ) . ')/';
200 }
201
202 // For custom post type archives
203 $cpts = array_intersect( $this->model->get_translated_post_types(), get_post_types( array( '_builtin' => false ) ) );
204 $cpts = $cpts ? '#post_type=(' . implode( '|', $cpts ) . ')#' : '';
205
206 foreach ( $rules as $key => $rule ) {
207 // Special case for translated post types and taxonomies to allow canonical redirection
208 if ( $this->options['force_lang'] && in_array( $filter, array_merge( $this->model->get_translated_post_types(), $this->model->get_translated_taxonomies() ) ) ) {
209
210 /**
211 * Filters the rewrite rules to modify
212 *
213 * @since 1.9.1
214 *
215 * @param bool $modify whether to modify or not the rule, defaults to true
216 * @param array $rule original rewrite rule
217 * @param string $filter current set of rules being modified
218 * @param string|bool $archive custom post post type archive name or false if it is not a cpt archive
219 */
220 if ( isset( $slug ) && apply_filters( 'pll_modify_rewrite_rule', true, array( $key => $rule ), $filter, false ) ) {
221 $newrules[ $slug . str_replace( $wp_rewrite->root, '', ltrim( $key, '^' ) ) ] = str_replace(
222 array( '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?' ),
223 array( '[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&' ),
224 $rule
225 ); // Should be enough!
226 }
227
228 $newrules[ $key ] = $rule;
229 }
230
231 // Rewrite rules filtered by language
232 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'] ) ) {
233
234 /** This filter is documented in include/links-directory.php */
235 if ( apply_filters( 'pll_modify_rewrite_rule', true, array( $key => $rule ), $filter, empty( $matches[1] ) ? false : $matches[1] ) ) {
236 if ( isset( $slug ) ) {
237 $newrules[ $slug . str_replace( $wp_rewrite->root, '', ltrim( $key, '^' ) ) ] = str_replace(
238 array( '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?' ),
239 array( '[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&' ),
240 $rule
241 ); // Should be enough!
242 }
243
244 if ( $this->options['hide_default'] ) {
245 $newrules[ $key ] = str_replace( '?', '?lang=' . $this->options['default_lang'] . '&', $rule );
246 }
247 } else {
248 $newrules[ $key ] = $rule;
249 }
250 }
251
252 // Unmodified rules
253 else {
254 $newrules[ $key ] = $rule;
255 }
256 }
257
258 // The home rewrite rule
259 if ( 'root' == $filter && isset( $slug ) ) {
260 $newrules[ $slug . '?$' ] = $wp_rewrite->index . '?lang=$matches[1]';
261 }
262
263 return $newrules;
264 }
265 }
266