PluginProbe
Polylang / 3.8.9
Polylang v3.8.9
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 / class-polylang.php

class-polylang.php in Polylang 3.8.9, at src/class-polylang.php

294 lines 8.3 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 use WP_Syntex\Polylang\Options\Options;
7 use WP_Syntex\Polylang\Options\Registry as Options_Registry;
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit; // Don't access directly
11 }
12
13 // Default directory to store user data such as custom flags
14 if ( ! defined( 'PLL_LOCAL_DIR' ) ) {
15 define( 'PLL_LOCAL_DIR', WP_CONTENT_DIR . '/polylang' );
16 }
17
18 // Includes local config file if exists
19 if ( is_readable( PLL_LOCAL_DIR . '/pll-config.php' ) ) {
20 include_once PLL_LOCAL_DIR . '/pll-config.php';
21 }
22
23 /**
24 * Controls the plugin, as well as activation, and deactivation
25 *
26 * @since 0.1
27 *
28 * @template TPLLClass of PLL_Base
29 */
30 class Polylang {
31
32 /**
33 * Constructor
34 *
35 * @since 0.1
36 */
37 public function __construct() {
38 require_once __DIR__ . '/functions.php'; // VIP functions
39
40 // Plugin initialization
41 // Take no action before all plugins are loaded
42 add_action( 'plugins_loaded', array( $this, 'init' ), 1 );
43
44 // Override load text domain waiting for the language to be defined
45 // Here for plugins which load text domain as soon as loaded :(
46 if ( ! defined( 'PLL_OLT' ) || PLL_OLT ) {
47 PLL_OLT_Manager::instance();
48 }
49
50 /*
51 * Loads the compatibility with some plugins and themes.
52 * Loaded as soon as possible as we may need to act before other plugins are loaded.
53 */
54 if ( ! defined( 'PLL_PLUGINS_COMPAT' ) || PLL_PLUGINS_COMPAT ) {
55 PLL_Integrations::instance();
56 }
57 }
58
59 /**
60 * Tells whether the current request is an ajax request on frontend or not
61 *
62 * @since 2.2
63 *
64 * @return bool
65 */
66 public static function is_ajax_on_front() {
67 // Special test for plupload which does not use jquery ajax and thus does not pass our ajax prefilter
68 // Special test for customize_save done in frontend but for which we want to load the admin
69 $in = isset( $_REQUEST['action'] ) && in_array( sanitize_key( $_REQUEST['action'] ), array( 'upload-attachment', 'customize_save' ) ); // phpcs:ignore WordPress.Security.NonceVerification
70 $is_ajax_on_front = wp_doing_ajax() && empty( $_REQUEST['pll_ajax_backend'] ) && ! $in; // phpcs:ignore WordPress.Security.NonceVerification
71
72 /**
73 * Filters whether the current request is an ajax request on front.
74 *
75 * @since 2.3
76 *
77 * @param bool $is_ajax_on_front Whether the current request is an ajax request on front.
78 */
79 return apply_filters( 'pll_is_ajax_on_front', $is_ajax_on_front );
80 }
81
82 /**
83 * Is the current request a REST API request?
84 * Inspired by WP::parse_request()
85 * Needed because at this point, the constant REST_REQUEST is not defined yet
86 *
87 * @since 2.4.1
88 *
89 * @return bool
90 */
91 public static function is_rest_request() {
92 // Handle pretty permalinks.
93 $home_path = trim( (string) wp_parse_url( home_url(), PHP_URL_PATH ), '/' );
94 $home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) );
95
96 $req_uri = trim( (string) wp_parse_url( pll_get_requested_url(), PHP_URL_PATH ), '/' );
97 $req_uri = (string) preg_replace( $home_path_regex, '', $req_uri );
98 $req_uri = trim( $req_uri, '/' );
99 $req_uri = str_replace( 'index.php', '', $req_uri );
100 $req_uri = trim( $req_uri, '/' );
101
102 // And also test rest_route query string parameter is not empty for plain permalinks.
103 $query_string = array();
104 wp_parse_str( (string) wp_parse_url( pll_get_requested_url(), PHP_URL_QUERY ), $query_string );
105 $rest_route = isset( $query_string['rest_route'] ) && is_string( $query_string['rest_route'] ) ? trim( $query_string['rest_route'], '/' ) : false;
106
107 return 0 === strpos( $req_uri, rest_get_url_prefix() . '/' ) || ! empty( $rest_route );
108 }
109
110 /**
111 * Tells if we are in the wizard process.
112 *
113 * @since 2.7
114 *
115 * @return bool
116 */
117 public static function is_wizard() {
118 return isset( $_GET['page'] ) && ! empty( $_GET['page'] ) && 'mlang_wizard' === sanitize_key( $_GET['page'] ); // phpcs:ignore WordPress.Security.NonceVerification
119 }
120
121 /**
122 * Defines constants
123 * May be overridden by a plugin if set before plugins_loaded, 1
124 *
125 * @since 1.6
126 *
127 * @return void
128 */
129 public static function define_constants() {
130 // Cookie name. no cookie will be used if set to false
131 if ( ! defined( 'PLL_COOKIE' ) ) {
132 define( 'PLL_COOKIE', 'pll_language' );
133 }
134
135 // Backward compatibility with Polylang < 2.3
136 if ( ! defined( 'PLL_AJAX_ON_FRONT' ) ) {
137 define( 'PLL_AJAX_ON_FRONT', self::is_ajax_on_front() );
138 }
139
140 // Admin
141 if ( ! defined( 'PLL_ADMIN' ) ) {
142 define( 'PLL_ADMIN', wp_doing_cron() || ( defined( 'WP_CLI' ) && WP_CLI ) || ( is_admin() && ! PLL_AJAX_ON_FRONT ) );
143 }
144
145 // Settings page whatever the tab except for the wizard which needs to be an admin process.
146 if ( ! defined( 'PLL_SETTINGS' ) ) {
147 define( 'PLL_SETTINGS', is_admin() && ( ( isset( $_GET['page'] ) && 0 === strpos( sanitize_key( $_GET['page'] ), 'mlang' ) && ! self::is_wizard() ) || ! empty( $_REQUEST['pll_ajax_settings'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification
148 }
149 }
150
151 /**
152 * Polylang initialization
153 * setups models and separate admin and frontend
154 *
155 * @since 1.2
156 *
157 * @return void
158 */
159 public function init() {
160 self::define_constants();
161
162 // Plugin options.
163 add_action( 'pll_init_options_for_blog', array( Options_Registry::class, 'register' ) );
164 $options = new Options();
165
166 // Plugin upgrade
167 if ( ! empty( $options['version'] ) ) {
168 if ( version_compare( $options['version'], POLYLANG_VERSION, '<' ) ) {
169 $upgrade = new PLL_Upgrade( $options );
170 if ( ! $upgrade->upgrade() ) { // If the version is too old
171 return;
172 }
173 }
174 } else {
175 // In some edge cases, it's possible that no options were found in the database.
176 $options['version'] = POLYLANG_VERSION;
177 }
178
179 /**
180 * Filter the model class to use
181 * /!\ this filter is fired *before* the $polylang object is available
182 *
183 * @since 1.5
184 *
185 * @param string $class either PLL_Model or PLL_Admin_Model
186 */
187 $class = apply_filters( 'pll_model', PLL_SETTINGS || self::is_wizard() ? 'PLL_Admin_Model' : 'PLL_Model' );
188 /** @var PLL_Model $model */
189 $model = new $class( $options );
190
191 if ( ! $model->has_languages() ) {
192 /**
193 * Fires when no language has been defined yet
194 * Used to load overridden textdomains
195 *
196 * @since 1.2
197 */
198 do_action( 'pll_no_language_defined' );
199 }
200
201 $class = '';
202
203 if ( PLL_SETTINGS ) {
204 $class = 'PLL_Settings';
205 } elseif ( PLL_ADMIN ) {
206 $class = 'PLL_Admin';
207 } elseif ( self::is_rest_request() ) {
208 $class = 'PLL_REST_Request';
209 } elseif ( $model->has_languages() ) {
210 $class = 'PLL_Frontend';
211 }
212
213 /**
214 * Filters the class to use to instantiate the $polylang object
215 *
216 * @since 2.6
217 *
218 * @param string $class A class name.
219 */
220 $class = apply_filters( 'pll_context', $class );
221
222 if ( ! empty( $class ) ) {
223 /** @phpstan-var class-string<TPLLClass> $class */
224 $this->init_context( $class, $model );
225 }
226 }
227
228 /**
229 * Polylang initialization.
230 * Setups the Polylang Context, loads the modules and init Polylang.
231 *
232 * @since 3.6
233 *
234 * @param string $class The class name.
235 * @param PLL_Model $model Instance of PLL_Model.
236 * @return PLL_Base
237 *
238 * @phpstan-param class-string<TPLLClass> $class
239 * @phpstan-return TPLLClass
240 */
241 public function init_context( string $class, PLL_Model $model ): PLL_Base {
242 global $polylang;
243
244 $links_model = $model->get_links_model();
245 $polylang = new $class( $links_model );
246
247 /**
248 * Fires after Polylang's model init.
249 * This is the best place to register a custom table (see `PLL_Model`'s constructor).
250 * /!\ This hook is fired *before* the $polylang object is available.
251 * /!\ The languages are also not available yet.
252 *
253 * @since 3.4
254 *
255 * @param PLL_Model $model Polylang model.
256 */
257 do_action( 'pll_model_init', $model );
258
259 $model->maybe_create_language_terms();
260
261 /**
262 * Fires after the $polylang object is created and before the API is loaded
263 *
264 * @since 2.0
265 *
266 * @param object $polylang
267 */
268 do_action_ref_array( 'pll_pre_init', array( &$polylang ) );
269
270 // Loads the API
271 require_once POLYLANG_DIR . '/src/api.php';
272
273 // Loads the modules.
274 $load_scripts = require POLYLANG_DIR . '/src/modules/module-build.php';
275
276 foreach ( $load_scripts as $load_script ) {
277 require_once POLYLANG_DIR . "/src/modules/{$load_script}/load.php";
278 }
279
280 $polylang->init();
281
282 /**
283 * Fires after the $polylang object and the API is loaded
284 *
285 * @since 1.7
286 *
287 * @param object $polylang
288 */
289 do_action_ref_array( 'pll_init', array( &$polylang ) );
290
291 return $polylang;
292 }
293 }
294