PluginProbe
Whols – Wholesale Prices and B2B Store Solution for WooCommerce / 2.4.12
Whols – Wholesale Prices and B2B Store Solution for WooCommerce v2.4.12
2.4.12 2.4.11 trunk 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 All 55 releases
whols / whols.php

whols.php in Whols – Wholesale Prices and B2B Store Solution for WooCommerce 2.4.12, at whols.php

560 lines 18.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Whols - Wholesale Prices and B2B Store Solution for WooCommerce
4 * Plugin URI: https://wpwhols.com/
5 * Description: This plugin provides all the necessary features that you will ever need to sell wholesale products from your WooCommerce online store.
6 * Version: 2.4.12
7 * Author: HasThemes
8 * Author URI: https://hasthemes.com
9 * License: GPL v2 or later
10 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
11 * Text Domain: whols
12 * Requires at least: 5.0
13 * Requires PHP: 7.4
14 * Requires Plugins: woocommerce
15 * Domain Path: /languages
16 */
17
18 use const Whols\PL_VERSION;
19 use const Whols\PL_FILE;
20 use const Whols\PL_PATH;
21 use const Whols\PL_URL;
22
23 // If this file is accessed directly, exit
24 if ( ! defined( 'ABSPATH' ) ) {
25 exit;
26 }
27
28 /**
29 * Main Whols class
30 *
31 * @since 1.0.0
32 */
33
34 final class Whols_Lite {
35
36 /**
37 * Whols version
38 *
39 * @since 1.0.0
40 */
41 public $version = '2.4.12';
42
43 /**
44 * The single instance of the class
45 *
46 * @since 1.0.0
47 */
48 protected static $_instance = null;
49
50 /**
51 * Main Whols Instance
52 *
53 * Ensures only one instance of Whols is loaded or can be loaded
54 *
55 * @since 1.0.0
56 */
57 public static function instance() {
58 if ( is_null( self::$_instance ) ) {
59 self::$_instance = new self();
60 }
61 return self::$_instance;
62 }
63
64 /**
65 * Whols Constructor
66 *
67 * @since 1.0.0
68 */
69 private function __construct() {
70 $this->define_constants();
71 $this->includes();
72 $this->run();
73 }
74
75 /**
76 * Define the required constants
77 *
78 * @since 1.0.0
79 */
80 /**
81 * Two constant sets are defined on purpose, and both are in use:
82 *
83 * - WHOLS_* global, consumed by the older files that sit outside a
84 * namespace (this bootstrap, includes/functions.php, and the
85 * Admin/ classes that predate the namespace migration).
86 * - Whols\PL_* namespaced, consumed unqualified by the files declaring
87 * `namespace Whols;` — the newer modules.
88 *
89 * Removing either set breaks live callers. Pro does not read these; it
90 * defines its own Whols_Pro\PL_* set in whols-pro.php.
91 */
92 private function define_constants() {
93 define( 'WHOLS_VERSION', $this->version );
94 define( 'WHOLS_FILE', __FILE__ );
95 define( 'WHOLS_PATH', __DIR__ );
96 define( 'WHOLS_URL', plugins_url( '', WHOLS_FILE ) );
97 define( 'WHOLS_ASSETS', WHOLS_URL . '/assets' );
98
99 define( 'Whols\PL_VERSION', $this->version );
100 define( 'Whols\PL_FILE', __FILE__ );
101 define( 'Whols\PL_PATH', __DIR__ );
102 define( 'Whols\PL_URL', plugins_url( '', PL_FILE ) );
103 define( 'Whols\PL_ASSETS', PL_URL . '/assets' );
104 }
105
106 /**
107 * Include files
108 *
109 * @since 1.0.0
110 */
111 public function includes() {
112 /**
113 * Including plugin file for secutiry purpose
114 */
115 if ( ! function_exists( 'is_plugin_active' ) ) {
116 include_once ABSPATH . 'wp-admin/includes/plugin.php';
117 }
118
119 if ( ! function_exists( 'get_current_screen' ) ) {
120 require_once ABSPATH . '/wp-admin/includes/screen.php';
121 }
122
123 /**
124 * Load files
125 */
126 require_once WHOLS_PATH . '/includes/functions.php';
127 require_once WHOLS_PATH . '/includes/ajax-actions.php';
128
129 if ( ! class_exists( 'CSF' ) ) {
130 require_once WHOLS_PATH .'/includes/Admin/csf-settings-custom/classes/setup.class.php';
131 require_once WHOLS_PATH . '/includes/Admin/csf-fields/CSF_Field_registration_details.php';
132 }
133
134 // Assets
135 require_once WHOLS_PATH . '/includes/class-assets-manager.php';
136
137 require_once WHOLS_PATH . '/includes/Admin.php';
138
139 require_once WHOLS_PATH . '/includes/Admin/Custom_Posts.php';
140 require_once WHOLS_PATH . '/includes/Admin/Custom_Taxonomies.php';
141 require_once WHOLS_PATH . '/includes/Admin/Wholesaler_Request_Metabox.php';
142 require_once WHOLS_PATH . '/includes/Admin/Product_Metabox.php';
143 require_once WHOLS_PATH . '/includes/Admin/User_Metabox.php';
144 require_once WHOLS_PATH . '/includes/Admin/Role_Cat_Metabox.php';
145 require_once WHOLS_PATH . '/includes/Admin/Product_Category_Metabox.php';
146 require_once WHOLS_PATH . '/includes/Admin/Role_Manager.php';
147 require_once WHOLS_PATH . '/includes/Admin/Custom_Columns.php';
148 require_once WHOLS_PATH . '/includes/Admin/class-polylang-integration.php';
149 require_once WHOLS_PATH . '/includes/Admin/CSF_Field_whols_image.php';
150 require_once WHOLS_PATH . '/includes/Admin/recommended-plugins/class.recommended-plugins.php';
151 require_once WHOLS_PATH . '/includes/Admin/recommended-plugins/recommendations.php';
152 require_once WHOLS_PATH . '/includes/Admin/install-manager/class-install-manager.php';
153 require_once WHOLS_PATH . '/includes/Admin/Diagnostic_Data.php';
154 require_once WHOLS_PATH . '/includes/Admin/class-menu-manager.php';
155 require_once WHOLS_PATH . '/includes/Admin/Notice_Handler.php';
156
157 if ( is_admin() ) {
158 require_once WHOLS_PATH . '/includes/Admin/class-dashboard-widget-api.php';
159 require_once WHOLS_PATH . '/includes/Admin/class-dashboard-widget.php';
160 }
161
162 require_once WHOLS_PATH . '/includes/Frontend.php';
163 require_once WHOLS_PATH . '/includes/Frontend/Wholesaler_Login_Register.php';
164 require_once WHOLS_PATH . '/includes/Frontend/Woo_Config.php';
165
166 require_once WHOLS_PATH . '/includes/class-wholesale-product-pricing.php';
167
168 // Popup
169 require_once WHOLS_PATH . '/includes/popup/class-whols-popup.php';
170
171 // Quote
172 require_once WHOLS_PATH . '/includes/request-a-quote/class-request-quote.php';
173
174 // Save Order List
175 require_once WHOLS_PATH . '/includes/save-order-list/class-save-order-list.php';
176
177 // Product Quick Edit Fields
178 require_once WHOLS_PATH . '/includes/Admin/class-product-quick-edit-fields.php';
179
180 require_once WHOLS_PATH . '/includes/Email_Notifications.php';
181 require_once WHOLS_PATH . '/includes/Manage_Order.php';
182 require_once WHOLS_PATH . '/includes/Compatibility.php';
183
184 // Vue settings
185 require_once PL_PATH . '/includes/vue-settings/class-init.php';
186 }
187
188 /**
189 * First initialization of the plugin
190 *
191 * @since 1.0.0
192 */
193 private function run() {
194 register_activation_hook( __FILE__, array( $this, 'register_activation_hook_cb' ) );
195
196 if ( ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
197 add_action( 'admin_notices', array( $this, 'build_dependencies_notice' ) );
198 } else {
199 // Set up localisation.
200 add_action( 'init', array( $this, 'load_plugin_textdomain' ) );
201
202 // Finally initialize this plugin
203 add_action( 'plugins_loaded', array( $this, 'plugins_loaded_cb' ) );
204
205 // Redirect after activation
206 add_action('admin_init', array( $this, 'do_activation_redirect') );
207 }
208 }
209
210 /**
211 * Do stuff upon plugin activation
212 *
213 * @since 1.0.0
214 */
215 public function register_activation_hook_cb() {
216 // deactivate the pro plugin if active
217 if ( ! function_exists('is_plugin_active') ){
218 include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
219 }
220
221 if( is_plugin_active('whols-pro/whols-pro.php') ){
222 add_action('update_option_active_plugins', function(){
223 deactivate_plugins('whols-pro/whols-pro.php');
224 });
225 }
226
227 $installed = get_option( 'whols_installed' );
228
229 if ( ! $installed ) {
230 update_option( 'whols_installed', time() );
231 }
232
233 update_option( 'whols_version', WHOLS_VERSION );
234 update_option( 'whols_do_activation_redirect', 'yes' );
235
236 // Save initial settings if not already.
237 $existing_settings = get_option('whols_options');
238 if ( empty($existing_settings) ) {
239 $defaults = Whols\Vue_Settings\Settings_Defaults::get_defaults();
240 update_option( 'whols_options', $defaults );
241 }
242
243 $this->maybe_create_registration_page();
244 }
245
246 /**
247 * Create the registration page on first activation and select it.
248 *
249 * Runs at most once per site: the `whols_registration_page_created` flag is
250 * set even when nothing is created, so a merchant who later deletes the page
251 * or clears the setting does not get one forced back on them.
252 *
253 * @since 2.4.11
254 */
255 private function maybe_create_registration_page() {
256 if ( get_option( 'whols_registration_page_created' ) ) {
257 return;
258 }
259
260 // Flag first: whatever happens below, this should never run again.
261 update_option( 'whols_registration_page_created', 'yes' );
262
263 $options = get_option( 'whols_options' );
264 $options = is_array( $options ) ? $options : array();
265
266 // Never overwrite a page the merchant already chose.
267 if ( ! empty( $options['registration_page'] ) ) {
268 return;
269 }
270
271 // Adopt a matching page instead of creating a duplicate slug. Only a
272 // published one: get_page_by_path() ignores post status, and selecting a
273 // trashed or draft page would 404 the registration form.
274 $existing = get_page_by_path( 'wholesale-registration' );
275
276 if ( $existing && 'publish' === get_post_status( $existing ) ) {
277 $page_id = $existing->ID;
278 } else {
279 $page_id = wp_insert_post( array(
280 'post_title' => __( 'Wholesale Registration', 'whols' ),
281 'post_name' => 'wholesale-registration',
282 'post_content' => '<!-- wp:shortcode -->[whols_registration_form]<!-- /wp:shortcode -->',
283 'post_status' => 'publish',
284 'post_type' => 'page',
285 'post_author' => get_current_user_id(),
286 ) );
287 }
288
289 if ( is_wp_error( $page_id ) || ! $page_id ) {
290 return;
291 }
292
293 // Cast to string: whols_pages_dropdown_options() emits string IDs, and the
294 // settings UI matches option values strictly. An int here stores correctly
295 // but leaves the dropdown looking empty.
296 $options['registration_page'] = (string) $page_id;
297 update_option( 'whols_options', $options );
298 }
299
300 /**
301 * Maybe redirect to the admin page
302 *
303 * Checks if the activation redirect flag is set and redirects to the admin page if needed
304 *
305 * @return void
306 */
307 public function do_activation_redirect() {
308 // Only run on admin page load
309 if ( ! is_admin() || wp_doing_ajax() ) {
310 return;
311 }
312
313 // Check if we should redirect
314 $redirect = get_option( 'whols_do_activation_redirect' );
315
316 if ( 'yes' === $redirect ) {
317 // Delete the redirect option to prevent multiple redirects
318 delete_option( 'whols_do_activation_redirect' );
319
320 $redirect_link = admin_url( 'admin.php?page=whols-admin' );
321
322 if( whols_should_show_onboarding() ){
323 $redirect_link = admin_url( 'admin.php?page=whols-admin#onboarding' );
324 }
325
326 // Redirect to the admin page
327 wp_safe_redirect( $redirect_link );
328 exit;
329 }
330 }
331
332 /**
333 * Load the plugin textdomain
334 *
335 * @since 1.0.0
336 */
337 public function load_plugin_textdomain() {
338 load_plugin_textdomain( 'whols', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
339 }
340
341 /**
342 * Initialize this plugin
343 *
344 * @since 1.0.0
345 */
346 public function plugins_loaded_cb() {
347 // Both admin + frontend
348 new Whols\Assets_Manager();
349 new Whols\Manage_Order();
350 new Whols\Compatibility();
351 new Whols\Admin\Custom_Posts();
352
353 // Prior this was instantiate only in the Frontend.php file
354 // The reason why moved it here is to load it on both frontend & admin because for using the has_shortcode function in the admin area too.
355 new Whols\Frontend\Wholesaler_Login_Register();
356
357 // Frontend
358 new Whols\Frontend();
359 new Whols\Frontend\Woo_Config();
360 new Whols\Request_Quote();
361
362 if ( is_admin() ) {
363 new Whols\Admin();
364 new Whols\Admin\Menu_Manager();
365 }
366
367 // Insert default role
368 add_action('init', array( $this, 'insert_default_term'), 12);
369
370 // Test mode
371 $this->init_test_mode();
372
373 // Notice
374 add_action( 'admin_head', function(){
375 $remote_banner_data = whols_get_plugin_remote_data();
376
377 if (!empty($remote_banner_data) && is_array($remote_banner_data)) {
378 foreach ($remote_banner_data as $banner) {
379 if (empty($banner['disable'])) {
380 Whols\Admin\Notice_Handler::set_notice($banner);
381 }
382 }
383 }
384 } );
385 }
386
387 /**
388 * Output a admin notice when build dependencies not met
389 *
390 * @since 1.0.0
391 */
392 public function build_dependencies_notice() {
393 $message = sprintf(
394 /*
395 * translators:
396 * 1: Whols.
397 * 2: WooCommerce.
398 */
399 esc_html__( '%1$s plugin requires the %2$s plugin to be installed and activated in order to work.', 'whols' ),
400 '<strong>' . esc_html__( 'Whols', 'whols' ) . '</strong>',
401 '<strong>' . esc_html__( 'WooCommerce', 'whols' ) . '</strong>'
402 );
403
404 printf( '<div class="notice notice-warning"><p>%1$s</p></div>', wp_kses_post($message) );
405 }
406
407 /**
408 * Create and set default role
409 */
410 public function insert_default_term(){
411 // check if category(term) exists
412 $cat_exists = term_exists('whols_default_role', 'whols_role_cat');
413
414 if ( !$cat_exists ) {
415 // if term is not exist, insert it
416 $new_cat = wp_insert_term(
417 esc_html__( 'Default Role', 'whols' ),
418 'whols_role_cat',
419 array(
420 'description' => esc_html__( 'Default Wholesale Role', 'whols' ),
421 'slug' => 'whols_default_role',
422 )
423 );
424 // wp_insert_term returns an array on success so we need to get the term_id from it
425 $default_cat_id = ($new_cat && is_array($new_cat)) ? $new_cat['term_id'] : false;
426 } else {
427 //if default category is already inserted, term_exists will return it's term_id
428 $default_cat_id = $cat_exists;
429 }
430
431 // Setting default_{$taxonomy} option value as our default term_id to make them default and non-removable (like default uncategorized WP category)
432 $stored_default_cat = get_option( 'whols_default_role' );
433
434 if ( empty( $stored_default_cat ) && $default_cat_id )
435 update_option( 'whols_default_role', $default_cat_id );
436 }
437
438 /**
439 * Implement test mode feature
440 * If test mode is enabled, it adds whols_default_role to the current logged in administrator user
441 * and if the test mode is disabled, it removes the whols_default_role from the administrator
442 */
443 public function init_test_mode(){
444 if( is_user_logged_in() && current_user_can('manage_options') ){
445
446 $current_user = wp_get_current_user();
447 $is_test_mode = whols_get_option('show_wholesale_price_for') === 'administrator' ? true : false;
448
449 $test_mode_meta = get_user_meta(get_current_user_id(), 'whols_test_mode', true );
450
451 if( $is_test_mode && !$test_mode_meta && !array_intersect($current_user->roles, array('whols_default_role')) ){
452 $current_user->add_role('whols_default_role');
453 update_user_meta( get_current_user_id(), 'whols_test_mode', 1 );
454 } elseif( !$is_test_mode && $test_mode_meta && array_intersect($current_user->roles, array('whols_default_role') ) ){
455 $current_user->remove_role('whols_default_role');
456 delete_user_meta( get_current_user_id(), 'whols_test_mode' );
457 }
458 }
459 }
460
461 }
462
463 /**
464 * Minimum PHP version this plugin can run on.
465 *
466 * Note: the `use const` statements at the top of this file are PHP 5.6+, so on
467 * PHP 5.5 and below this file fails to compile and the guard below is never
468 * reached. WordPress 5.1+ blocks activation via the `Requires PHP` header, so
469 * this guard covers the remaining cases: an existing install whose host
470 * downgrades PHP, or WordPress older than 5.1.
471 *
472 * @since 2.4.11
473 */
474 define( 'WHOLS_MINIMUM_PHP_VERSION', '7.4' );
475
476 /**
477 * Whether the current PHP version meets the plugin requirement
478 *
479 * @since 2.4.11
480 *
481 * @return bool
482 */
483 function whols_is_php_version_supported() {
484 return version_compare( PHP_VERSION, WHOLS_MINIMUM_PHP_VERSION, '>=' );
485 }
486
487 /**
488 * Admin notice shown when the PHP requirement is not met
489 *
490 * The plugin text domain is never loaded in this state, so the string stays in
491 * English regardless of locale.
492 *
493 * @since 2.4.11
494 */
495 function whols_php_version_notice() {
496 if ( ! current_user_can( 'activate_plugins' ) ) {
497 return;
498 }
499
500 printf(
501 '<div class="notice notice-error"><p>%s</p></div>',
502 esc_html(
503 sprintf(
504 /* translators: 1: required PHP version, 2: PHP version running on the server */
505 __( 'Whols requires PHP %1$s or higher. This site is running PHP %2$s, so the plugin has not been loaded. Ask your host to upgrade PHP.', 'whols' ),
506 WHOLS_MINIMUM_PHP_VERSION,
507 PHP_VERSION
508 )
509 )
510 );
511 }
512
513 /**
514 * Block activation outright on an unsupported PHP version
515 *
516 * Registered before Whols_Lite registers its own activation callback so this
517 * runs first and stops the rest of the activation routine.
518 *
519 * @since 2.4.11
520 */
521 function whols_php_version_activation_check() {
522 if ( whols_is_php_version_supported() ) {
523 return;
524 }
525
526 wp_die(
527 esc_html(
528 sprintf(
529 /* translators: 1: required PHP version, 2: PHP version running on the server */
530 __( 'Whols requires PHP %1$s or higher. This site is running PHP %2$s.', 'whols' ),
531 WHOLS_MINIMUM_PHP_VERSION,
532 PHP_VERSION
533 )
534 ),
535 esc_html__( 'Plugin Activation Error', 'whols' ),
536 array( 'back_link' => true )
537 );
538 }
539 register_activation_hook( __FILE__, 'whols_php_version_activation_check' );
540
541 /**
542 * Returns the main instance of Whols
543 *
544 * @since 1.0.0
545 */
546
547 function whols_lite() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
548 // Never build the object on an unsupported PHP version: the constructor
549 // includes files that use PHP 7.4+ syntax and would fatal at compile time.
550 if ( ! whols_is_php_version_supported() ) {
551 add_action( 'admin_notices', 'whols_php_version_notice' );
552 return null;
553 }
554
555 return Whols_Lite::instance();
556 }
557
558 // Kick-off the plugin
559 whols_lite();
560