class-sv-wc-framework-bootstrap.php
14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
<?php
/**
* WooCommerce Plugin Framework
*
* This source file is subject to the GNU General Public License v3.0
* that is bundled with this package in the file license.txt.
* It is also available through the world-wide-web at this URL:
* http://www.gnu.org/licenses/gpl-3.0.html
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@skyverge.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade the plugin to newer
* versions in the future. If you wish to customize the plugin for your
* needs please refer to http://www.skyverge.com
*
* @package SkyVerge/WooCommerce/Plugin/Classes
* @author SkyVerge
* @copyright Copyright (c) 2013-2016, SkyVerge, Inc.
* @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
*/
defined( 'ABSPATH' ) or exit;
if ( ! class_exists( 'SV_WC_Framework_Bootstrap' ) ) :
/**
* # SkyVerge WooCommerce Plugin Framework Bootstrap
*
* The purpose of this class is to find and load the highest versioned
* framework of the activated framework plugins, and then initialize any
* compatible framework plugins.
*
* @since 2.0.0
*/
class SV_WC_Framework_Bootstrap {
/** @var SV_WC_Framework_Bootstrap The single instance of the class */
protected static $instance = null;
/** @var array registered framework plugins */
protected $registered_plugins = array();
/** @var array registered and active framework plugins */
protected $active_plugins = array();
/** @var array of plugins that need to be updated due to an outdated framework */
protected $incompatible_framework_plugins = array();
/** @var array of plugins that require a newer version of WC */
protected $incompatible_wc_version_plugins = array();
/** @var array of plugins that require a newer version of WP */
protected $incompatible_wp_version_plugins = array();
/**
* Hidden constructor
*
* @since 2.0.0
*/
private function __construct() {
// load framework plugins once all plugins are loaded
add_action( 'plugins_loaded', array( $this, 'load_framework_plugins' ) );
// deactivate backwards-incompatible framework plugins if the admin isn't ready to upgrade old plugins
add_action( 'admin_init', array( $this, 'maybe_deactivate_framework_plugins' ) );
}
/**
* Instantiate the class singleton
*
* @since 2.0.0
* @return SV_WC_Framework_Bootstrap singleton instance
*/
public static function instance() {
if ( is_null( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Register a frameworked plugin
*
* @since 2.0.0
* @param string $version the framework version
* @param string $plugin_name the plugin name
* @param string $path the plugin path
* @param callable $callback function to initialize the plugin
* @param array $args optional plugin arguments. Possible arguments: 'is_payment_gateway', 'backwards_compatible'
*/
public function register_plugin( $version, $plugin_name, $path, $callback, $args = array() ) {
$this->registered_plugins[] = array( 'version' => $version, 'plugin_name' => $plugin_name, 'path' => $path, 'callback' => $callback, 'args' => $args );
}
/**
* Loads all registered framework plugins, first initializing the plugin
* framework by loading the highest versioned one.
*
* @since 2.0.0
*/
public function load_framework_plugins() {
// first sort the registered plugins by framework version
usort( $this->registered_plugins, array( $this, 'compare_frameworks' ) );
$loaded_framework = null;
foreach ( $this->registered_plugins as $plugin ) {
// load the first found (highest versioned) plugin framework class
if ( ! class_exists( 'SV_WC_Plugin' ) ) {
require_once( $this->get_plugin_path( $plugin['path'] ) . '/lib/skyverge/woocommerce/class-sv-wc-plugin.php' );
$loaded_framework = $plugin;
// the loaded plugin is always considered active (for the
// purposes of handling conflicts between this and other plugins
// with incompatible framework versions)
$this->active_plugins[] = $plugin;
}
// if the loaded version of the framework has a backwards compatibility requirement
// which is not met by the current plugin add an admin notice and move on without
// loading the plugin
if ( ! empty( $loaded_framework['args']['backwards_compatible'] ) && version_compare( $loaded_framework['args']['backwards_compatible'], $plugin['version'], '>' ) ) {
$this->incompatible_framework_plugins[] = $plugin;
// next plugin
continue;
}
// if a plugin defines a minimum WC version which is not met, render a notice and skip loading the plugin
if ( ! empty( $plugin['args']['minimum_wc_version'] ) && version_compare( $this->get_wc_version(), $plugin['args']['minimum_wc_version'], '<' ) ) {
$this->incompatible_wc_version_plugins[] = $plugin;
// next plugin
continue;
}
// if a plugin defines a minimum WP version which is not met, render a notice and skip loading the plugin
if ( ! empty( $plugin['args']['minimum_wp_version'] ) && version_compare( get_bloginfo( 'version' ), $plugin['args']['minimum_wp_version'], '<' ) ) {
$this->incompatible_wp_version_plugins[] = $plugin;
// next plugin
continue;
}
// add this plugin to the active list
if ( ! in_array( $plugin, $this->active_plugins ) ) {
$this->active_plugins[] = $plugin;
}
// load the first found (highest versioned) payment gateway framework class, as needed
if ( isset( $plugin['args']['is_payment_gateway'] ) && ! class_exists( 'SV_WC_Payment_Gateway' ) ) {
require_once( $this->get_plugin_path( $plugin['path'] ) . '/lib/skyverge/woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php' );
}
// initialize the plugin
$plugin['callback']();
}
// render update notices
if ( ( $this->incompatible_framework_plugins || $this->incompatible_wc_version_plugins || $this->incompatible_wp_version_plugins ) && is_admin() && ! is_ajax() && ! has_action( 'admin_notices', array( $this, 'render_update_notices' ) ) ) {
add_action( 'admin_notices', array( $this, 'render_update_notices' ) );
}
/**
* WC Plugin Framework Plugins Loaded Action.
*
* Fired when all frameworked plugins are loaded. Frameworked plugins can
* hook into this action rather than `plugins_loaded`/`woocommerce_loaded`
* as needed.
*
* @since 2.0.0
*/
do_action( 'sv_wc_framework_plugins_loaded' );
}
/** Admin methods ******************************************************/
/**
* Deactivate backwards-incompatible framework plugins, which will allow
* plugins with an older version of the framework to be active. Useful when
* the admin isn't ready to upgrade older plugins yet needs them to still
* function (e.g. a payment gateway)
*
* @since 4.0.0
*/
public function maybe_deactivate_framework_plugins() {
if ( isset( $_GET['sv_wc_framework_deactivate_newer'] ) ) {
if ( 'yes' == $_GET['sv_wc_framework_deactivate_newer'] ) {
// don't want to just deactivate all active plugins willy-nilly if there's no incompatible plugins
if ( count( $this->incompatible_framework_plugins ) == 0 ) {
return;
}
$plugins = array();
foreach ( $this->active_plugins as $plugin ) {
$plugins[] = plugin_basename( $plugin['path'] );
}
// deactivate all "active" frameworked plugins, these will be the newest, backwards-incompatible ones
deactivate_plugins( $plugins );
// redirect to the inactive plugin admin page, with a message indicating the number of plugins deactivated
wp_redirect( admin_url( 'plugins.php?plugin_status=inactive&sv_wc_framework_deactivate_newer=' . count( $plugins ) ) );
exit;
} else {
// we're on the inactive plugin page and we've deactivated one or more plugins
add_action( 'admin_notices', array( $this, 'render_deactivation_notice' ) );
}
}
}
/**
* Render a notice with a count of the backwards incompatible frameworked
* plugins that were deactivated
*
* @since 4.0.0
*/
public function render_deactivation_notice() {
echo '<div class="updated"><p>';
echo $_GET['sv_wc_framework_deactivate_newer'] > 1 ?
sprintf( 'Deactivated %d plugins', $_GET['sv_wc_framework_deactivate_newer'] ) :
'Deactivated one plugin';
echo '</p></div>';
}
/**
* Render a notice to update any plugins with incompatible framework
* versions, or incompatiblities with the current WooCommerce or WordPress
* versions
*
* @since 2.0.0
*/
public function render_update_notices() {
// must update plugin notice
if ( ! empty( $this->incompatible_framework_plugins ) ) {
$plugin_count = count( $this->incompatible_framework_plugins );
echo '<div class="error">';
// describe the problem
echo '<p>';
echo esc_html( _n( 'The following plugin is inactive because it is out of date and requires a newer version to function properly:', 'The following plugins are inactive because they are out of date and require a newer version to function properly:', $plugin_count, 'woocommerce-plugin-framework' ) );
echo '</p>';
// add a incompatible plugin list
echo '<ul>';
foreach ( $this->incompatible_framework_plugins as $plugin ) {
printf( '<li>%s</li>', $plugin['plugin_name'] );
}
echo '</ul>';
// describe the way to fix it
echo '<p>';
printf(
/* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag, %3$s - <em> tag, %4$s - </em> tag, %5$s - <a> tag, %6$s - </a> tag */
esc_html( _n( 'To reactivate, please %1$supdate the above plugin (recommended)%2$s %3$sor%4$s %5$sdeactivate the following%6$s:', 'To reactivate, please %1$supdate the above plugins (recommended)%2$s %3$sor%4$s %5$sdeactivate the following%6$s:', $plugin_count, 'woocommerce-plugin-framework' ) ),
'<a href="' . esc_url( admin_url( 'update-core.php' ) ) . '">', '</a>',
'<em>', '</em>',
'<a href="' . esc_url( admin_url( 'plugins.php?sv_wc_framework_deactivate_newer=yes' ) ) . '">', '</a>'
);
echo '</p>';
// add the list of active plugins
echo '<ul>';
foreach ( $this->active_plugins as $plugin ) {
printf( '<li>%s</li>', $plugin['plugin_name'] );
}
echo '</ul>';
echo '</div>';
}
// must update WC notice
if ( ! empty( $this->incompatible_wc_version_plugins ) ) {
printf( '<div class="error"><p>%s</p><ul>', count( $this->incompatible_wc_version_plugins ) > 1 ? esc_html__( 'The following plugins are inactive because they require a newer version of WooCommerce:', 'woocommerce-plugin-framework' ) : esc_html__( 'The following plugin is inactive because it requires a newer version of WooCommerce:', 'woocommerce-plugin-framework' ) );
foreach ( $this->incompatible_wc_version_plugins as $plugin ) {
/* translators: Placeholders: %1$s - plugin name, %2$s - WooCommerce version number */
echo '<li>' . sprintf( esc_html__( '%1$s requires WooCommerce %2$s or newer', 'woocommerce-plugin-framework' ), $plugin['plugin_name'], $plugin['args']['minimum_wc_version'] ) . '</li>';
}
/* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
echo '</ul><p>' . sprintf( esc_html__( 'Please %1$supdate WooCommerce%2$s', 'woocommerce-plugin-framework' ), '<a href="' . admin_url( 'update-core.php' ) . '">', ' »</a>' ) . '</p></div>';
}
// must update WP notice
if ( ! empty( $this->incompatible_wp_version_plugins ) ) {
printf( '<div class="error"><p>%s</p><ul>', count( $this->incompatible_wp_version_plugins ) > 1 ? 'The following plugins are inactive because they require a newer version of WordPress:' : 'The following plugin is inactive because it requires a newer version of WordPress:' );
foreach ( $this->incompatible_wp_version_plugins as $plugin ) {
printf( '<li>%s requires WordPress %s or newer</li>', $plugin['plugin_name'], $plugin['args']['minimum_wp_version'] );
}
echo '</ul><p>Please <a href="' . admin_url( 'update-core.php' ) . '">update WordPress »</a></p></div>';
}
}
/** Helper methods ******************************************************/
/**
* Is the WooCommerce plugin installed and active? This method is handy for
* frameworked plugins that are listed on wordpress.org and thus don't have
* access to the Woo Helper functions bundled with WooThemes-listed plugins.
*
* Notice: For now you can't rely on this method being available, since the
* bootstrap class is the only piece of the framework which is loaded
* simply according to the lexical order of plugin directories. Therefore
* to use, you should first check that this method exists, or if you really
* need to check for WooCommerce being active, define your own method.
*
* @since 4.0.0
* @return boolean true if the WooCommerce plugin is installed and active
*/
public static function is_woocommerce_active() {
$active_plugins = (array) get_option( 'active_plugins', array() );
if ( is_multisite() ) {
$active_plugins = array_merge( $active_plugins, get_site_option( 'active_sitewide_plugins', array() ) );
}
return in_array( 'woocommerce/woocommerce.php', $active_plugins ) || array_key_exists( 'woocommerce/woocommerce.php', $active_plugins );
}
/**
* Compare the two framework versions. Returns -1 if $a is less than $b, 0 if
* they're equal, and 1 if $a is greater than $b
*
* @since 2.0.0
* @param array $a first registered plugin to compare
* @param array $b second registered plugin to compare
* @return int -1 if $a is less than $b, 0 if they're equal, and 1 if $a is greater than $b
*/
public function compare_frameworks( $a, $b ) {
// compare versions without the operator argument, so we get a -1, 0 or 1 result
return version_compare( $b['version'], $a['version'] );
}
/**
* Returns the plugin path for the given $file
*
* @since 2.0.0
* @param string $file the file
* @return string plugin path
*/
public function get_plugin_path( $file ) {
return untrailingslashit( plugin_dir_path( $file ) );
}
/**
* Returns the WooCommerce version number, backwards compatible to
* WC 1.5
*
* @since 3.0.0
* @return null|string
*/
protected function get_wc_version() {
if ( defined( 'WC_VERSION' ) && WC_VERSION ) return WC_VERSION;
if ( defined( 'WOOCOMMERCE_VERSION' ) && WOOCOMMERCE_VERSION ) return WOOCOMMERCE_VERSION;
return null;
}
}
// instantiate the class
SV_WC_Framework_Bootstrap::instance();
endif;