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

class-polylang.php in Polylang 3.7.4, at include/class-polylang.php

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