PluginProbe
Polylang / 2.7
Polylang v2.7
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 2.7, at include/class-polylang.php

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