PluginProbe ʕ •ᴥ•ʔ
WPML Multilingual & Multicurrency for WooCommerce / 5.5.7
WPML Multilingual & Multicurrency for WooCommerce v5.5.7
5.5.7 5.3.8 5.3.9 5.4.3 5.4.4 5.4.5 5.5.1 5.5.1.1 5.5.2.2 5.5.2.3 5.5.3 5.5.3.1 5.5.4 5.5.5 5.5.6 trunk 0.9 1.0 1.1 1.2 1.3 1.4 1.5 2.0 2.2 2.3 2.3.1 2.3.2 3.0 3.0.1 3.1 3.2 3.2.1 3.2.2 3.3 3.3.1 3.3.2 3.3.3 3.3.4 3.4 3.4.1 3.4.2 3.4.3 3.5 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.6 3.6.1 3.6.10 3.6.11 3.6.2 3.6.3 3.6.4 3.6.5 3.6.5.1 3.6.6 3.6.7 3.6.8 3.6.9 3.7 3.7.1 3.7.10 3.7.11 3.7.12 3.7.13 3.7.14 3.7.15 3.7.16 3.7.2 3.7.3 3.7.4 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.9.0 3.9.1 3.9.1.1 3.9.2 3.9.3 3.9.4 3.9.5 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.10.2 4.10.3 4.10.4 4.11.2 4.11.3.2 4.11.5 4.11.6 4.12.1 4.12.4 4.12.5 4.12.6 4.2.0 4.2.0.1 4.2.1 4.2.1.1 4.2.10 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.7.1 4.2.8 4.2.8.1 4.2.9 4.3.0 4.3.1 4.3.2 4.3.2.1 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.4.0 4.4.1 4.4.2 4.4.2.1 4.5.0 4.6.0 4.6.1 4.6.2 4.6.2.1 4.6.3 4.6.5 4.6.6 4.6.7 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.7.5 4.7.6 4.7.7 4.7.8 4.7.9 4.8.0 4.9.0 4.9.1 5.0.1 5.0.2 5.1.1 5.1.2 5.1.3 5.2.0 5.2.1 5.3.2 5.3.3.1 5.3.4 5.3.5 5.3.6 5.3.7
woocommerce-multilingual / vendor / wpml-shared / wpml-lib-dependencies / src / dependencies / class-wpml-dependencies.php
woocommerce-multilingual / vendor / wpml-shared / wpml-lib-dependencies / src / dependencies Last commit date
class-wpml-core-version-check.php 1 month ago class-wpml-dependencies.php 1 month ago class-wpml-php-version-check.php 1 month ago
class-wpml-dependencies.php
346 lines
1 <?php
2
3 class WPML_Dependencies {
4 protected static $instance;
5 private $admin_notice;
6 private $current_product;
7 private $current_version = array();
8 private $expected_versions = array();
9 private $installed_plugins = array();
10 private $invalid_plugins = array();
11 private $valid_plugins = array();
12 private $validation_results = array();
13
14 public $data_key = 'wpml_dependencies:';
15 public $needs_validation_key = 'wpml_dependencies:needs_validation';
16
17 private function __construct() {
18 if ( null === self::$instance ) {
19 $this->remove_old_admin_notices();
20 $this->init_hooks();
21 }
22 }
23
24 private function collect_data() {
25 $active_plugins = wp_get_active_and_valid_plugins();
26 $this->init_bundle( $active_plugins );
27 foreach ( $active_plugins as $plugin ) {
28 $this->add_installed_plugin( $plugin );
29 }
30 }
31
32 protected function remove_old_admin_notices() {
33 if ( class_exists( 'WPML_Bundle_Check' ) ) {
34 global $WPML_Bundle_Check;
35
36 remove_action( 'admin_notices', array( $WPML_Bundle_Check, 'admin_notices_action' ) );
37 }
38 }
39
40 private function init_hooks() {
41 add_action( 'init', array( $this, 'init_plugins_action' ) );
42 add_action( 'extra_plugin_headers', array( $this, 'extra_plugin_headers_action' ) );
43 add_action( 'admin_notices', array( $this, 'admin_notices_action' ) );
44 add_action( 'activated_plugin', array( $this, 'activated_plugin_action' ) );
45 add_action( 'deactivated_plugin', array( $this, 'deactivated_plugin_action' ) );
46 add_action( 'upgrader_process_complete', array( $this, 'upgrader_process_complete_action' ), 10, 2 );
47 add_action( 'load-plugins.php', array( $this, 'run_validation_on_plugins_page' ) );
48 }
49
50 public function run_validation_on_plugins_page() {
51 $this->reset_validation();
52 }
53
54 public function activated_plugin_action() {
55 $this->reset_validation();
56 }
57
58 public function deactivated_plugin_action() {
59 $this->reset_validation();
60 }
61
62 public function upgrader_process_complete_action( $upgrader_object, $options ) {
63 if ( 'update' === $options['action'] && 'plugin' === $options['type'] ) {
64 $this->reset_validation();
65 }
66 }
67
68 private function reset_validation() {
69 update_option( $this->needs_validation_key, true );
70 $this->validate_plugins();
71 }
72
73 private function flag_as_validated() {
74 update_option( $this->needs_validation_key, false );
75 }
76
77 private function needs_validation() {
78 return get_option( $this->needs_validation_key );
79 }
80
81 public function admin_notices_action() {
82 $this->maybe_init_admin_notice();
83 if ( $this->admin_notice && ( is_admin() && ! $this->is_doing_ajax_cron_or_xmlrpc() ) ) {
84 echo $this->admin_notice;
85 }
86 }
87
88 private function is_doing_ajax_cron_or_xmlrpc() {
89 return ( $this->is_doing_ajax() || $this->is_doing_cron() || $this->is_doing_xmlrpc() );
90 }
91
92 private function is_doing_ajax() {
93 return ( defined( 'DOING_AJAX' ) && DOING_AJAX );
94 }
95
96 private function is_doing_cron() {
97 return ( defined( 'DOING_CRON' ) && DOING_CRON );
98 }
99
100 private function is_doing_xmlrpc() {
101 return ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST );
102 }
103
104 public function extra_plugin_headers_action( array $extra_headers = array() ) {
105 $new_extra_header = array(
106 'PluginSlug' => 'Plugin Slug',
107 );
108
109 return array_merge( $new_extra_header, (array) $extra_headers );
110 }
111
112 public static function get_instance() {
113 if ( null === self::$instance ) {
114 self::$instance = new WPML_Dependencies();
115 }
116
117 return self::$instance;
118 }
119
120 public function get_plugins() {
121 return $this->installed_plugins;
122 }
123
124 public function init_plugins_action() {
125 if ( $this->needs_validation() && is_admin() && ! $this->is_doing_ajax_cron_or_xmlrpc() ) {
126 $this->init_plugins();
127 $this->validate_plugins();
128 $this->flag_as_validated();
129 }
130 }
131
132 private function init_plugins() {
133 if ( ! $this->installed_plugins ) {
134 if ( ! function_exists( 'get_plugin_data' ) ) {
135 include_once ABSPATH . '/wp-admin/includes/plugin.php';
136 }
137 if ( function_exists( 'get_plugin_data' ) ) {
138 $this->collect_data();
139 }
140 }
141 update_option( $this->data_key . 'installed_plugins', $this->installed_plugins );
142 }
143
144 private function init_bundle( array $active_plugins ) {
145
146 foreach ( $active_plugins as $plugin_file ) {
147 $filename = dirname( $plugin_file ) . '/wpml-dependencies.json';
148 if ( file_exists( $filename ) ) {
149 $data = file_get_contents( $filename );
150 $bundle = json_decode( $data, true );
151 $this->set_expected_versions( $bundle );
152 }
153 }
154 }
155
156 private function add_installed_plugin( $plugin ) {
157 $data = get_plugin_data( $plugin );
158 $plugin_dir = realpath( dirname( $plugin ) );
159
160 $wp_plugin_dir = realpath( WP_PLUGIN_DIR ) . DIRECTORY_SEPARATOR;
161 if ( false !== $plugin_dir && $wp_plugin_dir !== $plugin_dir ) {
162 $plugin_folder = str_replace( $wp_plugin_dir, '', $plugin_dir );
163 $plugin_slug = $this->guess_plugin_slug( $data, $plugin_folder );
164
165 if ( $this->is_valid_plugin( $plugin_slug ) ) {
166 $this->installed_plugins[ $plugin_slug ] = $data['Version'];
167 }
168 }
169 }
170
171 private function set_expected_versions( array $bundle ) {
172 foreach ( $bundle as $plugin => $version ) {
173 if ( ! array_key_exists( $plugin, $this->expected_versions ) ) {
174 $this->expected_versions[ $plugin ] = $version;
175 } else {
176 if ( version_compare( $this->expected_versions[ $plugin ], $version, '<' ) ) {
177 $this->expected_versions[ $plugin ] = $version;
178 }
179 }
180 }
181 }
182
183 private function guess_plugin_slug( $plugin_data, $plugin_folder ) {
184 $plugin_slug = null;
185 $plugin_slug = $plugin_folder;
186 if ( array_key_exists( 'Plugin Slug', $plugin_data ) && $plugin_data['Plugin Slug'] ) {
187 $plugin_slug = $plugin_data['Plugin Slug'];
188 }
189
190 return $plugin_slug;
191 }
192
193 private function validate_plugins() {
194 $validation_results = $this->get_plugins_validation();
195
196 $this->valid_plugins = array();
197 $this->invalid_plugins = array();
198 foreach ( $validation_results as $plugin => $validation_result ) {
199 if ( true === $validation_result ) {
200 $this->valid_plugins[] = $plugin;
201 } else {
202 $this->invalid_plugins[] = $plugin;
203 }
204 }
205
206 update_option( $this->data_key . 'valid_plugins', $this->valid_plugins );
207 update_option( $this->data_key . 'invalid_plugins', $this->invalid_plugins );
208 update_option( $this->data_key . 'expected_versions', $this->expected_versions );
209 }
210
211 public function get_plugins_validation() {
212 foreach ( $this->installed_plugins as $plugin => $version ) {
213 $this->current_product = $plugin;
214 if ( $this->is_valid_plugin() ) {
215 $this->current_version = $version;
216 $validation_result = $this->is_plugin_version_valid();
217 $this->validation_results[ $plugin ] = $validation_result;
218 }
219 }
220
221 return $this->validation_results;
222 }
223
224 private function is_valid_plugin( $product = false ) {
225 $result = false;
226
227 if ( ! $product ) {
228 $product = $this->current_product;
229 }
230 if ( $product ) {
231 $versions = $this->get_expected_versions();
232 $result = array_key_exists( $product, $versions );
233 }
234
235 return $result;
236 }
237
238 public function is_plugin_version_valid() {
239 $expected_version = $this->filter_version( $this->get_expected_product_version() );
240
241 return $expected_version ? version_compare( $this->filter_version( $this->current_version ), $expected_version, '>=' ) : null;
242 }
243
244 private function filter_version( $version ) {
245 return preg_replace( '#[^\d.].*#', '', $version );
246 }
247
248 public function get_expected_versions() {
249 return $this->expected_versions;
250 }
251
252 private function get_expected_product_version( $product = false ) {
253 $result = null;
254
255 if ( ! $product ) {
256 $product = $this->current_product;
257 }
258 if ( $product ) {
259 $versions = $this->get_expected_versions();
260
261 $result = isset( $versions[ $product ] ) ? $versions[ $product ] : null;
262 }
263
264 return $result;
265 }
266
267 private function maybe_init_admin_notice() {
268 $this->admin_notice = null;
269 $this->installed_plugins = get_option( $this->data_key . 'installed_plugins', [] );
270 $this->invalid_plugins = get_option( $this->data_key . 'invalid_plugins', [] );
271 $this->expected_versions = get_option( $this->data_key . 'expected_versions', [] );
272 $this->valid_plugins = get_option( $this->data_key . 'valid_plugins', [] );
273
274 if ( $this->has_invalid_plugins() ) {
275 $notice_paragraphs = array();
276
277 $notice_paragraphs[] = $this->get_invalid_plugins_report_header();
278 $notice_paragraphs[] = $this->get_invalid_plugins_report_list();
279 $notice_paragraphs[] = $this->get_invalid_plugins_report_footer();
280
281 $this->admin_notice = '<div class="error wpml-admin-notice">';
282 $this->admin_notice .= '<h3>' . __( 'WPML Update is Incomplete', 'sitepress' ) . '</h3>';
283 $this->admin_notice .= '<p>' . implode( '</p><p>', $notice_paragraphs ) . '</p>';
284 $this->admin_notice .= '</div>';
285 }
286 }
287
288 public function has_invalid_plugins() {
289 return count( $this->invalid_plugins );
290 }
291
292 private function get_invalid_plugins_report_header() {
293 if ( $this->has_valid_plugins() ) {
294 if ( count( $this->valid_plugins ) === 1 ) {
295 $paragraph = __( 'You are running updated %s, but the following component is not updated:', 'sitepress' );
296 $paragraph = sprintf( $paragraph, '<strong>' . $this->valid_plugins[0] . '</strong>' );
297 } else {
298 $paragraph = __( 'You are running updated %s and %s, but the following components are not updated:', 'sitepress' );
299 $first_valid_plugins = implode( ', ', array_slice( $this->valid_plugins, 0, - 1 ) );
300 $last_valid_plugin = array_slice( $this->valid_plugins, - 1 );
301 $paragraph = sprintf( $paragraph, '<strong>' . $first_valid_plugins . '</strong>', '<strong>' . $last_valid_plugin[0] . '</strong>' );
302 }
303 } else {
304 $paragraph = __( 'The following components are not updated:', 'sitepress' );
305 }
306
307 return $paragraph;
308 }
309
310 private function get_invalid_plugins_report_list() {
311 /* translators: %s: Version number */
312 $required_version = __( 'required version: %s', 'sitepress' );
313 $invalid_plugins_list = '<ul class="ul-disc">';
314 foreach ( $this->invalid_plugins as $invalid_plugin ) {
315 $plugin_name_html = '<li data-installed-version="' . $this->installed_plugins[ $invalid_plugin ] . '">';
316 $required_version_string = '';
317 if ( isset( $this->expected_versions[ $invalid_plugin ] ) ) {
318 $required_version_string = ' (' . sprintf( $required_version, $this->expected_versions[ $invalid_plugin ] ) . ')';
319 }
320 $plugin_name_html .= $invalid_plugin . $required_version_string;
321 $plugin_name_html .= '</li>';
322
323 $invalid_plugins_list .= $plugin_name_html;
324 }
325 $invalid_plugins_list .= '</ul>';
326
327 return $invalid_plugins_list;
328 }
329
330 private function get_invalid_plugins_report_footer() {
331 $wpml_org_url = '<a href="https://wpml.org/account/" title="WPML.org account">' . __( 'WPML.org account', 'sitepress' ) . '</a>';
332
333 $notice_paragraph = __( 'Your site will not work as it should in this configuration', 'sitepress' );
334 $notice_paragraph .= ' ';
335 $notice_paragraph .= __( 'Please update all components which you are using.', 'sitepress' );
336 $notice_paragraph .= ' ';
337 $notice_paragraph .= sprintf( __( 'For WPML components you can receive updates from your %s or automatically, after you register WPML.', 'sitepress' ), $wpml_org_url );
338
339 return $notice_paragraph;
340 }
341
342 private function has_valid_plugins() {
343 return $this->valid_plugins && count( $this->valid_plugins );
344 }
345 }
346