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

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

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