PluginProbe
Polylang / 3.7.1
Polylang v3.7.1
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 / frontend / frontend.php

frontend.php in Polylang 3.7.1, at frontend/frontend.php

301 lines 8.6 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 // Filters posts by language
92 add_action( 'parse_query', array( $this, 'parse_query' ), 6 );
93
94 // Not before 'check_canonical_url'
95 if ( ! defined( 'PLL_AUTO_TRANSLATE' ) || PLL_AUTO_TRANSLATE ) {
96 add_action( 'template_redirect', array( $this, 'auto_translate' ), 7 );
97 }
98
99 add_action( 'admin_bar_menu', array( $this, 'remove_customize_admin_bar' ), 41 ); // After WP_Admin_Bar::add_menus
100
101 /*
102 * Static front page and page for posts.
103 *
104 * Early instantiated to be able to correctly initialize language properties.
105 * Also loaded in customizer preview, directly reading the request as we act before WP.
106 */
107 if ( 'page' === get_option( 'show_on_front' ) || ( isset( $_REQUEST['wp_customize'] ) && 'on' === $_REQUEST['wp_customize'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
108 $this->static_pages = new PLL_Frontend_Static_Pages( $this );
109 }
110
111 $this->model->set_languages_ready();
112 }
113
114 /**
115 * Setups the language chooser based on options
116 *
117 * @since 1.2
118 */
119 public function init() {
120 parent::init();
121
122 $this->links = new PLL_Frontend_Links( $this );
123
124 $this->default_term = new PLL_Default_Term( $this );
125 $this->default_term->add_hooks();
126
127 // Setup the language chooser
128 $c = array( 'Content', 'Url', 'Url', 'Domain' );
129 $class = 'PLL_Choose_Lang_' . $c[ $this->options['force_lang'] ];
130 $this->choose_lang = new $class( $this );
131 $this->choose_lang->init();
132
133 // Need to load nav menu class early to correctly define the locations in the customizer when the language is set from the content
134 $this->nav_menu = new PLL_Frontend_Nav_Menu( $this );
135 }
136
137 /**
138 * Setups filters and nav menus once the language has been defined
139 *
140 * @since 1.2
141 *
142 * @return void
143 */
144 public function pll_language_defined() {
145 // Filters
146 $this->filters_links = new PLL_Frontend_Filters_Links( $this );
147 $this->filters = new PLL_Frontend_Filters( $this );
148 $this->filters_search = new PLL_Frontend_Filters_Search( $this );
149 $this->filters_widgets = new PLL_Frontend_Filters_Widgets( $this );
150
151 /*
152 * Redirects to canonical url before WordPress redirect_canonical
153 * but after Nextgen Gallery which hacks $_SERVER['REQUEST_URI'] !!!
154 * and restores it in 'template_redirect' with priority 1.
155 */
156 $this->canonical = new PLL_Canonical( $this );
157 add_action( 'template_redirect', array( $this->canonical, 'check_canonical_url' ), 4 );
158
159 // Auto translate for Ajax
160 if ( ( ! defined( 'PLL_AUTO_TRANSLATE' ) || PLL_AUTO_TRANSLATE ) && wp_doing_ajax() ) {
161 $this->auto_translate();
162 }
163 }
164
165 /**
166 * When querying multiple taxonomies, makes sure that the language is not the queried object.
167 *
168 * @since 1.8
169 *
170 * @param WP_Query $query WP_Query object.
171 * @return void
172 */
173 public function parse_tax_query( $query ) {
174 $pll_query = new PLL_Query( $query, $this->model );
175 $queried_taxonomies = $pll_query->get_queried_taxonomies();
176
177 if ( ! empty( $queried_taxonomies ) && 'language' == reset( $queried_taxonomies ) ) {
178 $query->tax_query->queried_terms['language'] = array_shift( $query->tax_query->queried_terms );
179 }
180 }
181
182 /**
183 * Modifies some query vars to "hide" that the language is a taxonomy and avoid conflicts.
184 *
185 * @since 1.2
186 *
187 * @param WP_Query $query WP_Query object.
188 * @return void
189 */
190 public function parse_query( $query ) {
191 $qv = $query->query_vars;
192 $pll_query = new PLL_Query( $query, $this->model );
193 $taxonomies = $pll_query->get_queried_taxonomies();
194
195 // Allow filtering recent posts and secondary queries by the current language
196 if ( ! empty( $this->curlang ) ) {
197 $pll_query->filter_query( $this->curlang );
198 }
199
200 // Modifies query vars when the language is queried
201 if ( ! empty( $qv['lang'] ) || ( ! empty( $taxonomies ) && array( 'language' ) == array_values( $taxonomies ) ) ) {
202 // Do we query a custom taxonomy?
203 $taxonomies = array_diff( $taxonomies, array( 'language', 'category', 'post_tag' ) );
204
205 // Remove pages query when the language is set unless we do a search
206 // Take care not to break the single page, attachment and taxonomies queries!
207 if ( empty( $qv['post_type'] ) && ! $query->is_search && ! $query->is_singular && empty( $taxonomies ) && ! $query->is_category && ! $query->is_tag ) {
208 $query->set( 'post_type', 'post' );
209 }
210
211 // Unset the is_archive flag for language pages to prevent loading the archive template
212 // Keep archive flag for comment feed otherwise the language filter does not work
213 if ( empty( $taxonomies ) && ! $query->is_comment_feed && ! $query->is_post_type_archive && ! $query->is_date && ! $query->is_author && ! $query->is_category && ! $query->is_tag ) {
214 $query->is_archive = false;
215 }
216
217 // Unset the is_tax flag except if another custom tax is queried
218 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 ) ) {
219 $query->is_tax = false;
220 unset( $query->queried_object ); // FIXME useless?
221 }
222 }
223 }
224
225 /**
226 * Auto translate posts and terms ids
227 *
228 * @since 1.2
229 *
230 * @return void
231 */
232 public function auto_translate() {
233 $this->auto_translate = new PLL_Frontend_Auto_Translate( $this );
234 }
235
236 /**
237 * Resets some variables when the blog is switched.
238 * Overrides the parent method.
239 *
240 * @since 1.5.1
241 *
242 * @param int $new_blog_id New blog ID.
243 * @param int $prev_blog_id Previous blog ID.
244 * @return void
245 */
246 public function switch_blog( $new_blog_id, $prev_blog_id ) {
247 if ( (int) $new_blog_id === (int) $prev_blog_id ) {
248 // Do nothing if same blog.
249 return;
250 }
251
252 parent::switch_blog( $new_blog_id, $prev_blog_id );
253
254 // Need to check that some languages are defined when user is logged in, has several blogs, some without any languages.
255 if ( ! $this->is_active_on_current_site() || ! $this->model->has_languages() || ! did_action( 'pll_language_defined' ) ) {
256 return;
257 }
258
259 static $restore_curlang;
260
261 if ( empty( $restore_curlang ) ) {
262 $restore_curlang = $this->curlang->slug; // To always remember the current language through blogs.
263 }
264
265 $lang = $this->model->get_language( $restore_curlang );
266 $this->curlang = $lang ?: $this->model->get_default_language();
267 if ( empty( $this->curlang ) ) {
268 return;
269 }
270
271 if ( isset( $this->static_pages ) ) {
272 $this->static_pages->init();
273 }
274
275 // Send the slug instead of the locale here to avoid conflicts with same locales.
276 $this->load_strings_translations( $this->curlang->slug );
277 }
278
279 /**
280 * Remove the customize admin bar on front-end when using a block theme.
281 *
282 * WordPress removes the Customizer menu if a block theme is activated and no other plugins interact with it.
283 * As Polylang interacts with the Customizer, we have to delete this menu ourselves in the case of a block theme,
284 * unless another plugin than Polylang interacts with the Customizer.
285 *
286 * @since 3.2
287 *
288 * @return void
289 */
290 public function remove_customize_admin_bar() {
291 if ( ! $this->should_customize_menu_be_removed() ) {
292 return;
293 }
294
295 global $wp_admin_bar;
296
297 remove_action( 'wp_before_admin_bar_render', 'wp_customize_support_script' ); // To avoid the script launch.
298 $wp_admin_bar->remove_menu( 'customize' );
299 }
300 }
301