PluginProbe
Whols – Wholesale Prices and B2B Store Solution for WooCommerce / 2.4.11
Whols – Wholesale Prices and B2B Store Solution for WooCommerce v2.4.11
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.11, at whols.php

555 lines 18.5 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.11
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.11';
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 require_once WHOLS_PATH . '/includes/Frontend.php';
158 require_once WHOLS_PATH . '/includes/Frontend/Wholesaler_Login_Register.php';
159 require_once WHOLS_PATH . '/includes/Frontend/Woo_Config.php';
160
161 require_once WHOLS_PATH . '/includes/class-wholesale-product-pricing.php';
162
163 // Popup
164 require_once WHOLS_PATH . '/includes/popup/class-whols-popup.php';
165
166 // Quote
167 require_once WHOLS_PATH . '/includes/request-a-quote/class-request-quote.php';
168
169 // Save Order List
170 require_once WHOLS_PATH . '/includes/save-order-list/class-save-order-list.php';
171
172 // Product Quick Edit Fields
173 require_once WHOLS_PATH . '/includes/Admin/class-product-quick-edit-fields.php';
174
175 require_once WHOLS_PATH . '/includes/Email_Notifications.php';
176 require_once WHOLS_PATH . '/includes/Manage_Order.php';
177 require_once WHOLS_PATH . '/includes/Compatibility.php';
178
179 // Vue settings
180 require_once PL_PATH . '/includes/vue-settings/class-init.php';
181 }
182
183 /**
184 * First initialization of the plugin
185 *
186 * @since 1.0.0
187 */
188 private function run() {
189 register_activation_hook( __FILE__, array( $this, 'register_activation_hook_cb' ) );
190
191 if ( ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
192 add_action( 'admin_notices', array( $this, 'build_dependencies_notice' ) );
193 } else {
194 // Set up localisation.
195 add_action( 'init', array( $this, 'load_plugin_textdomain' ) );
196
197 // Finally initialize this plugin
198 add_action( 'plugins_loaded', array( $this, 'plugins_loaded_cb' ) );
199
200 // Redirect after activation
201 add_action('admin_init', array( $this, 'do_activation_redirect') );
202 }
203 }
204
205 /**
206 * Do stuff upon plugin activation
207 *
208 * @since 1.0.0
209 */
210 public function register_activation_hook_cb() {
211 // deactivate the pro plugin if active
212 if ( ! function_exists('is_plugin_active') ){
213 include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
214 }
215
216 if( is_plugin_active('whols-pro/whols-pro.php') ){
217 add_action('update_option_active_plugins', function(){
218 deactivate_plugins('whols-pro/whols-pro.php');
219 });
220 }
221
222 $installed = get_option( 'whols_installed' );
223
224 if ( ! $installed ) {
225 update_option( 'whols_installed', time() );
226 }
227
228 update_option( 'whols_version', WHOLS_VERSION );
229 update_option( 'whols_do_activation_redirect', 'yes' );
230
231 // Save initial settings if not already.
232 $existing_settings = get_option('whols_options');
233 if ( empty($existing_settings) ) {
234 $defaults = Whols\Vue_Settings\Settings_Defaults::get_defaults();
235 update_option( 'whols_options', $defaults );
236 }
237
238 $this->maybe_create_registration_page();
239 }
240
241 /**
242 * Create the registration page on first activation and select it.
243 *
244 * Runs at most once per site: the `whols_registration_page_created` flag is
245 * set even when nothing is created, so a merchant who later deletes the page
246 * or clears the setting does not get one forced back on them.
247 *
248 * @since 2.4.11
249 */
250 private function maybe_create_registration_page() {
251 if ( get_option( 'whols_registration_page_created' ) ) {
252 return;
253 }
254
255 // Flag first: whatever happens below, this should never run again.
256 update_option( 'whols_registration_page_created', 'yes' );
257
258 $options = get_option( 'whols_options' );
259 $options = is_array( $options ) ? $options : array();
260
261 // Never overwrite a page the merchant already chose.
262 if ( ! empty( $options['registration_page'] ) ) {
263 return;
264 }
265
266 // Adopt a matching page instead of creating a duplicate slug. Only a
267 // published one: get_page_by_path() ignores post status, and selecting a
268 // trashed or draft page would 404 the registration form.
269 $existing = get_page_by_path( 'wholesale-registration' );
270
271 if ( $existing && 'publish' === get_post_status( $existing ) ) {
272 $page_id = $existing->ID;
273 } else {
274 $page_id = wp_insert_post( array(
275 'post_title' => __( 'Wholesale Registration', 'whols' ),
276 'post_name' => 'wholesale-registration',
277 'post_content' => '<!-- wp:shortcode -->[whols_registration_form]<!-- /wp:shortcode -->',
278 'post_status' => 'publish',
279 'post_type' => 'page',
280 'post_author' => get_current_user_id(),
281 ) );
282 }
283
284 if ( is_wp_error( $page_id ) || ! $page_id ) {
285 return;
286 }
287
288 // Cast to string: whols_pages_dropdown_options() emits string IDs, and the
289 // settings UI matches option values strictly. An int here stores correctly
290 // but leaves the dropdown looking empty.
291 $options['registration_page'] = (string) $page_id;
292 update_option( 'whols_options', $options );
293 }
294
295 /**
296 * Maybe redirect to the admin page
297 *
298 * Checks if the activation redirect flag is set and redirects to the admin page if needed
299 *
300 * @return void
301 */
302 public function do_activation_redirect() {
303 // Only run on admin page load
304 if ( ! is_admin() || wp_doing_ajax() ) {
305 return;
306 }
307
308 // Check if we should redirect
309 $redirect = get_option( 'whols_do_activation_redirect' );
310
311 if ( 'yes' === $redirect ) {
312 // Delete the redirect option to prevent multiple redirects
313 delete_option( 'whols_do_activation_redirect' );
314
315 $redirect_link = admin_url( 'admin.php?page=whols-admin' );
316
317 if( whols_should_show_onboarding() ){
318 $redirect_link = admin_url( 'admin.php?page=whols-admin#onboarding' );
319 }
320
321 // Redirect to the admin page
322 wp_safe_redirect( $redirect_link );
323 exit;
324 }
325 }
326
327 /**
328 * Load the plugin textdomain
329 *
330 * @since 1.0.0
331 */
332 public function load_plugin_textdomain() {
333 load_plugin_textdomain( 'whols', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
334 }
335
336 /**
337 * Initialize this plugin
338 *
339 * @since 1.0.0
340 */
341 public function plugins_loaded_cb() {
342 // Both admin + frontend
343 new Whols\Assets_Manager();
344 new Whols\Manage_Order();
345 new Whols\Compatibility();
346 new Whols\Admin\Custom_Posts();
347
348 // Prior this was instantiate only in the Frontend.php file
349 // 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.
350 new Whols\Frontend\Wholesaler_Login_Register();
351
352 // Frontend
353 new Whols\Frontend();
354 new Whols\Frontend\Woo_Config();
355 new Whols\Request_Quote();
356
357 if ( is_admin() ) {
358 new Whols\Admin();
359 new Whols\Admin\Menu_Manager();
360 }
361
362 // Insert default role
363 add_action('init', array( $this, 'insert_default_term'), 12);
364
365 // Test mode
366 $this->init_test_mode();
367
368 // Notice
369 add_action( 'admin_head', function(){
370 $remote_banner_data = whols_get_plugin_remote_data();
371
372 if (!empty($remote_banner_data) && is_array($remote_banner_data)) {
373 foreach ($remote_banner_data as $banner) {
374 if (empty($banner['disable'])) {
375 Whols\Admin\Notice_Handler::set_notice($banner);
376 }
377 }
378 }
379 } );
380 }
381
382 /**
383 * Output a admin notice when build dependencies not met
384 *
385 * @since 1.0.0
386 */
387 public function build_dependencies_notice() {
388 $message = sprintf(
389 /*
390 * translators:
391 * 1: Whols.
392 * 2: WooCommerce.
393 */
394 esc_html__( '%1$s plugin requires the %2$s plugin to be installed and activated in order to work.', 'whols' ),
395 '<strong>' . esc_html__( 'Whols', 'whols' ) . '</strong>',
396 '<strong>' . esc_html__( 'WooCommerce', 'whols' ) . '</strong>'
397 );
398
399 printf( '<div class="notice notice-warning"><p>%1$s</p></div>', wp_kses_post($message) );
400 }
401
402 /**
403 * Create and set default role
404 */
405 public function insert_default_term(){
406 // check if category(term) exists
407 $cat_exists = term_exists('whols_default_role', 'whols_role_cat');
408
409 if ( !$cat_exists ) {
410 // if term is not exist, insert it
411 $new_cat = wp_insert_term(
412 esc_html__( 'Default Role', 'whols' ),
413 'whols_role_cat',
414 array(
415 'description' => esc_html__( 'Default Wholesale Role', 'whols' ),
416 'slug' => 'whols_default_role',
417 )
418 );
419 // wp_insert_term returns an array on success so we need to get the term_id from it
420 $default_cat_id = ($new_cat && is_array($new_cat)) ? $new_cat['term_id'] : false;
421 } else {
422 //if default category is already inserted, term_exists will return it's term_id
423 $default_cat_id = $cat_exists;
424 }
425
426 // Setting default_{$taxonomy} option value as our default term_id to make them default and non-removable (like default uncategorized WP category)
427 $stored_default_cat = get_option( 'whols_default_role' );
428
429 if ( empty( $stored_default_cat ) && $default_cat_id )
430 update_option( 'whols_default_role', $default_cat_id );
431 }
432
433 /**
434 * Implement test mode feature
435 * If test mode is enabled, it adds whols_default_role to the current logged in administrator user
436 * and if the test mode is disabled, it removes the whols_default_role from the administrator
437 */
438 public function init_test_mode(){
439 if( is_user_logged_in() && current_user_can('manage_options') ){
440
441 $current_user = wp_get_current_user();
442 $is_test_mode = whols_get_option('show_wholesale_price_for') === 'administrator' ? true : false;
443
444 $test_mode_meta = get_user_meta(get_current_user_id(), 'whols_test_mode', true );
445
446 if( $is_test_mode && !$test_mode_meta && !array_intersect($current_user->roles, array('whols_default_role')) ){
447 $current_user->add_role('whols_default_role');
448 update_user_meta( get_current_user_id(), 'whols_test_mode', 1 );
449 } elseif( !$is_test_mode && $test_mode_meta && array_intersect($current_user->roles, array('whols_default_role') ) ){
450 $current_user->remove_role('whols_default_role');
451 delete_user_meta( get_current_user_id(), 'whols_test_mode' );
452 }
453 }
454 }
455
456 }
457
458 /**
459 * Minimum PHP version this plugin can run on.
460 *
461 * Note: the `use const` statements at the top of this file are PHP 5.6+, so on
462 * PHP 5.5 and below this file fails to compile and the guard below is never
463 * reached. WordPress 5.1+ blocks activation via the `Requires PHP` header, so
464 * this guard covers the remaining cases: an existing install whose host
465 * downgrades PHP, or WordPress older than 5.1.
466 *
467 * @since 2.4.11
468 */
469 define( 'WHOLS_MINIMUM_PHP_VERSION', '7.4' );
470
471 /**
472 * Whether the current PHP version meets the plugin requirement
473 *
474 * @since 2.4.11
475 *
476 * @return bool
477 */
478 function whols_is_php_version_supported() {
479 return version_compare( PHP_VERSION, WHOLS_MINIMUM_PHP_VERSION, '>=' );
480 }
481
482 /**
483 * Admin notice shown when the PHP requirement is not met
484 *
485 * The plugin text domain is never loaded in this state, so the string stays in
486 * English regardless of locale.
487 *
488 * @since 2.4.11
489 */
490 function whols_php_version_notice() {
491 if ( ! current_user_can( 'activate_plugins' ) ) {
492 return;
493 }
494
495 printf(
496 '<div class="notice notice-error"><p>%s</p></div>',
497 esc_html(
498 sprintf(
499 /* translators: 1: required PHP version, 2: PHP version running on the server */
500 __( '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' ),
501 WHOLS_MINIMUM_PHP_VERSION,
502 PHP_VERSION
503 )
504 )
505 );
506 }
507
508 /**
509 * Block activation outright on an unsupported PHP version
510 *
511 * Registered before Whols_Lite registers its own activation callback so this
512 * runs first and stops the rest of the activation routine.
513 *
514 * @since 2.4.11
515 */
516 function whols_php_version_activation_check() {
517 if ( whols_is_php_version_supported() ) {
518 return;
519 }
520
521 wp_die(
522 esc_html(
523 sprintf(
524 /* translators: 1: required PHP version, 2: PHP version running on the server */
525 __( 'Whols requires PHP %1$s or higher. This site is running PHP %2$s.', 'whols' ),
526 WHOLS_MINIMUM_PHP_VERSION,
527 PHP_VERSION
528 )
529 ),
530 esc_html__( 'Plugin Activation Error', 'whols' ),
531 array( 'back_link' => true )
532 );
533 }
534 register_activation_hook( __FILE__, 'whols_php_version_activation_check' );
535
536 /**
537 * Returns the main instance of Whols
538 *
539 * @since 1.0.0
540 */
541
542 function whols_lite() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
543 // Never build the object on an unsupported PHP version: the constructor
544 // includes files that use PHP 7.4+ syntax and would fatal at compile time.
545 if ( ! whols_is_php_version_supported() ) {
546 add_action( 'admin_notices', 'whols_php_version_notice' );
547 return null;
548 }
549
550 return Whols_Lite::instance();
551 }
552
553 // Kick-off the plugin
554 whols_lite();
555