PluginProbe
Polylang / 3.8.6
Polylang v3.8.6
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 / src / frontend / frontend.php

frontend.php in Polylang 3.8.6, at src/frontend/frontend.php

320 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 * Main Polylang class when on frontend, accessible from @see PLL().
8 *
9 * @since 1.2
10 */
11 class PLL_Frontend extends PLL_Base {
12 /**
13 * Current language.
14 *
15 * @var PLL_Language|null
16 */
17 public $curlang;
18
19 /**
20 * @var PLL_Frontend_Auto_Translate|null
21 */
22 public $auto_translate;
23
24 /**
25 * The class selecting the current language.
26 *
27 * @var PLL_Choose_Lang|null
28 */
29 public $choose_lang;
30
31 /**
32 * @var PLL_Frontend_Filters|null
33 */
34 public $filters;
35
36 /**
37 * @var PLL_Frontend_Filters_Links|null
38 */
39 public $filters_links;
40
41 /**
42 * @var PLL_Frontend_Filters_Search|null
43 */
44 public $filters_search;
45
46 /**
47 * @var PLL_Frontend_Links|null
48 */
49 public $links;
50
51 /**
52 * @var PLL_Default_Term|null
53 */
54 public $default_term;
55
56 /**
57 * @var PLL_Frontend_Nav_Menu|null
58 */
59 public $nav_menu;
60
61 /**
62 * @var PLL_Frontend_Static_Pages|null
63 */
64 public $static_pages;
65
66 /**
67 * @var PLL_Frontend_Filters_Widgets|null
68 */
69 public $filters_widgets;
70
71 /**
72 * @var PLL_Canonical
73 */
74 public $canonical;
75
76 /**
77 * Constructor.
78 *
79 * @since 1.2
80 *
81 * @param PLL_Links_Model $links_model Reference to the links model.
82 */
83 public function __construct( &$links_model ) {
84 parent::__construct( $links_model );
85
86 add_action( 'pll_language_defined', array( $this, 'pll_language_defined' ), 1 );
87
88 // Avoids the language being the queried object when querying multiple taxonomies
89 add_action( 'parse_tax_query', array( $this, 'parse_tax_query' ), 1 );
90
91 // Prevent unnecessary queries to the DB.
92 add_action( 'parse_tax_query', array( $this, 'transform_query' ) );
93
94 // Filters posts by language
95 add_action( 'parse_query', array( $this, 'parse_query' ), 6 );
96
97 // Not before 'check_canonical_url'
98 if ( ! defined( 'PLL_AUTO_TRANSLATE' ) || PLL_AUTO_TRANSLATE ) {
99 add_action( 'template_redirect', array( $this, 'auto_translate' ), 7 );
100 }
101
102 add_action( 'admin_bar_menu', array( $this, 'remove_customize_admin_bar' ), 41 ); // After WP_Admin_Bar::add_menus
103
104 /*
105 * Static front page and page for posts.
106 *
107 * Early instantiated to be able to correctly initialize language properties.
108 * Also loaded in customizer preview, directly reading the request as we act before WP.
109 */
110 if ( 'page' === get_option( 'show_on_front' ) || ( isset( $_REQUEST['wp_customize'] ) && 'on' === $_REQUEST['wp_customize'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
111 $this->static_pages = new PLL_Frontend_Static_Pages( $this );
112 }
113
114 $this->model->set_languages_ready();
115 }
116
117 /**
118 * Setups the language chooser based on options
119 *
120 * @since 1.2
121 */
122 public function init() {
123 parent::init();
124
125 $this->links = new PLL_Frontend_Links( $this );
126
127 $this->default_term = new PLL_Default_Term( $this );
128 $this->default_term->add_hooks();
129
130 // Setup the language chooser
131 $c = array( 'Content', 'Url', 'Url', 'Domain' );
132 $class = 'PLL_Choose_Lang_' . $c[ $this->options['force_lang'] ];
133 $this->choose_lang = new $class( $this );
134 $this->choose_lang->init();
135
136 // Need to load nav menu class early to correctly define the locations in the customizer when the language is set from the content
137 $this->nav_menu = new PLL_Frontend_Nav_Menu( $this );
138 }
139
140 /**
141 * Setups filters and nav menus once the language has been defined
142 *
143 * @since 1.2
144 *
145 * @return void
146 */
147 public function pll_language_defined() {
148 // Filters
149 $this->filters_links = new PLL_Frontend_Filters_Links( $this );
150 $this->filters = new PLL_Frontend_Filters( $this );
151 $this->filters_search = new PLL_Frontend_Filters_Search( $this );
152 $this->filters_widgets = new PLL_Frontend_Filters_Widgets( $this );
153
154 /*
155 * Redirects to canonical url before WordPress redirect_canonical
156 * but after Nextgen Gallery which hacks $_SERVER['REQUEST_URI'] !!!
157 * and restores it in 'template_redirect' with priority 1.
158 */
159 $this->canonical = new PLL_Canonical( $this );
160 add_action( 'template_redirect', array( $this->canonical, 'check_canonical_url' ), 4 );
161
162 // Auto translate for Ajax
163 if ( ( ! defined( 'PLL_AUTO_TRANSLATE' ) || PLL_AUTO_TRANSLATE ) && wp_doing_ajax() ) {
164 $this->auto_translate();
165 }
166 }
167
168 /**
169 * When querying multiple taxonomies, makes sure that the language is not the queried object.
170 *
171 * @since 1.8
172 *
173 * @param WP_Query $query WP_Query object.
174 * @return void
175 */
176 public function parse_tax_query( $query ) {
177 $pll_query = new PLL_Query( $query, $this->model );
178 $queried_taxonomies = $pll_query->get_queried_taxonomies();
179
180 if ( ! empty( $queried_taxonomies ) && 'language' == reset( $queried_taxonomies ) ) {
181 $query->tax_query->queried_terms['language'] = array_shift( $query->tax_query->queried_terms );
182 }
183 }
184
185 /**
186 * Prevents unnecessary queries to the database by transforming
187 * a language query by `slug` to a language query by `term_taxonomy_id`.
188 *
189 * These extra queries occur when the language slug is displayed in the current's page URL, because WP wants a list
190 * of `term_taxonomy_id`.
191 *
192 * @since 3.8
193 *
194 * @param WP_Query $query WP_Query object.
195 * @return void
196 */
197 public function transform_query( $query ): void {
198 ( new PLL_Query( $query, $this->model ) )->transform_query();
199 }
200
201 /**
202 * Modifies some query vars to "hide" that the language is a taxonomy and avoid conflicts.
203 *
204 * @since 1.2
205 *
206 * @param WP_Query $query WP_Query object.
207 * @return void
208 */
209 public function parse_query( $query ) {
210 $qv = $query->query_vars;
211 $pll_query = new PLL_Query( $query, $this->model );
212 $taxonomies = $pll_query->get_queried_taxonomies();
213
214 // Allow filtering recent posts and secondary queries by the current language
215 if ( ! empty( $this->curlang ) ) {
216 $pll_query->filter_query( $this->curlang );
217 }
218
219 // Modifies query vars when the language is queried
220 if ( ! empty( $qv['lang'] ) || ( ! empty( $taxonomies ) && array( 'language' ) == array_values( $taxonomies ) ) ) {
221 // Do we query a custom taxonomy?
222 $taxonomies = array_diff( $taxonomies, array( 'language', 'category', 'post_tag' ) );
223
224 // Remove pages query when the language is set unless we do a search
225 // Take care not to break the single page, attachment and taxonomies queries!
226 if ( empty( $qv['post_type'] ) && ! $query->is_search && ! $query->is_singular && empty( $taxonomies ) && ! $query->is_category && ! $query->is_tag ) {
227 $query->set( 'post_type', 'post' );
228 }
229
230 // Unset the is_archive flag for language pages to prevent loading the archive template
231 // Keep archive flag for comment feed otherwise the language filter does not work
232 if ( empty( $taxonomies ) && ! $query->is_comment_feed && ! $query->is_post_type_archive && ! $query->is_date && ! $query->is_author && ! $query->is_category && ! $query->is_tag ) {
233 $query->is_archive = false;
234 }
235
236 // Unset the is_tax flag except if another custom tax is queried
237 if ( empty( $taxonomies ) && ( $query->is_category || $query->is_tag || $query->is_author || $query->is_post_type_archive || $query->is_date || $query->is_search || $query->is_feed ) ) {
238 $query->is_tax = false;
239 unset( $query->queried_object ); // FIXME useless?
240 }
241 }
242 }
243
244 /**
245 * Auto translate posts and terms ids
246 *
247 * @since 1.2
248 *
249 * @return void
250 */
251 public function auto_translate() {
252 $this->auto_translate = new PLL_Frontend_Auto_Translate( $this );
253 }
254
255 /**
256 * Resets some variables when the blog is switched.
257 * Overrides the parent method.
258 *
259 * @since 1.5.1
260 *
261 * @param int $new_blog_id New blog ID.
262 * @param int $prev_blog_id Previous blog ID.
263 * @return void
264 */
265 public function switch_blog( $new_blog_id, $prev_blog_id ) {
266 if ( (int) $new_blog_id === (int) $prev_blog_id ) {
267 // Do nothing if same blog.
268 return;
269 }
270
271 parent::switch_blog( $new_blog_id, $prev_blog_id );
272
273 // Need to check that some languages are defined when user is logged in, has several blogs, some without any languages.
274 if ( ! $this->is_active_on_current_site() || ! $this->model->has_languages() || ! did_action( 'pll_language_defined' ) ) {
275 return;
276 }
277
278 static $restore_curlang;
279
280 if ( empty( $restore_curlang ) ) {
281 $restore_curlang = $this->curlang->slug; // To always remember the current language through blogs.
282 }
283
284 $lang = $this->model->get_language( $restore_curlang );
285 $this->curlang = $lang ?: $this->model->get_default_language();
286 if ( empty( $this->curlang ) ) {
287 return;
288 }
289
290 if ( isset( $this->static_pages ) ) {
291 $this->static_pages->init();
292 }
293
294 // Send the slug instead of the locale here to avoid conflicts with same locales.
295 $this->load_strings_translations( $this->curlang->slug );
296 }
297
298 /**
299 * Remove the customize admin bar on front-end when using a block theme.
300 *
301 * WordPress removes the Customizer menu if a block theme is activated and no other plugins interact with it.
302 * As Polylang interacts with the Customizer, we have to delete this menu ourselves in the case of a block theme,
303 * unless another plugin than Polylang interacts with the Customizer.
304 *
305 * @since 3.2
306 *
307 * @return void
308 */
309 public function remove_customize_admin_bar() {
310 if ( ! $this->should_customize_menu_be_removed() ) {
311 return;
312 }
313
314 global $wp_admin_bar;
315
316 remove_action( 'wp_before_admin_bar_render', 'wp_customize_support_script' ); // To avoid the script launch.
317 $wp_admin_bar->remove_menu( 'customize' );
318 }
319 }
320