PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 2.3.0
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v2.3.0
2.3.0 2.2.0 2.1.1 2.1.0 2.0.0 1.10.0 1.9.1 1.9.0 1.2.1 1.2.2 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 All 59 releases
storeengine / storeengine.php

storeengine.php in StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More 2.3.0, at storeengine.php

416 lines 13.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: StoreEngine
4 * Plugin URI: https://storeengine.pro
5 * Description: Powerful WordPress eCommerce Plugin for Payments, Memberships, Affiliates, Sales & More
6 * Version: 2.3.0
7 * Author: Kodezen
8 * Author URI: http://kodezen.com
9 * License: GPL-3.0+
10 * License URI: http://www.gnu.org/licenses/gpl-3.0.txt
11 * Text Domain: storeengine
12 * Domain Path: /i18n/languages/
13 *
14 * Requires PHP: 7.4
15 * Requires at least: 6.5
16 * Tested up to: 7.0
17 *
18 * @package StoreEngine
19 */
20
21 use StoreEngine\ActionQueue;
22 use StoreEngine\Admin\Settings;
23 use StoreEngine\Classes\Cart;
24 use StoreEngine\Classes\Customer;
25 use StoreEngine\Classes\DownloadHandler;
26 use StoreEngine\Classes\Exceptions\StoreEngineException;
27 use StoreEngine\Classes\Logger;
28 use StoreEngine\Classes\StockManager;
29 use StoreEngine\Classes\Tax;
30 use StoreEngine\Classes\UrlPresigner;
31
32 if ( ! defined( 'ABSPATH' ) ) {
33 exit;
34 }
35
36 final class StoreEngine {
37
38 protected static ?StoreEngine $instance = null;
39
40 public ?Customer $customer = null;
41 public ?Cart $cart = null;
42
43 private function __construct() {
44 $this->define_constants();
45 // If a failed/interrupted update left core files missing, bail with an
46 // admin notice instead of fataling with a white screen.
47 if ( ! $this->load_dependency() ) {
48 return;
49 }
50
51 register_activation_hook( __FILE__, [ $this, 'activate' ] );
52 register_deactivation_hook( __FILE__, [ $this, 'deactivate' ] );
53 register_shutdown_function( [ $this, 'log_errors' ] );
54
55 Settings::load_settings();
56 StoreEngine\Installer::init();
57
58 add_action( 'activated_plugin', array( $this, 'activated_redirect' ), 10, 2 );
59 // Translations are loaded automatically by WordPress from the plugin
60 // header's `Text Domain` / `Domain Path` declarations (since 4.6), so
61 // we don't call load_plugin_textdomain ourselves. WP 6.7+ will throw
62 // "Translation loading triggered too early" if any code below calls
63 // __() before the `init` action fires — if that happens, fix the
64 // offending call site (defer to init), not by re-adding a loader here.
65 add_action( 'plugins_loaded', array( $this, 'on_plugins_loaded' ) );
66 add_action( 'storeengine_loaded', array( $this, 'init_plugin' ) );
67 add_action( 'init', array( $this, 'dispatch_post_hooks' ) );
68 }
69
70 public static function init(): StoreEngine {
71
72 if ( null === self::$instance ) {
73 self::$instance = new self();
74 }
75
76 return self::$instance;
77 }
78
79 public function define_constants() {
80 /**
81 * Defines CONSTANTS for Whole plugins.
82 */
83 define( 'STOREENGINE_VERSION', '2.3.0' );
84 define( 'STOREENGINE_DB_VERSION', '1.4' );
85 define( 'STOREENGINE_PLUGIN_FILE', __FILE__ );
86 define( 'STOREENGINE_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
87 define( 'STOREENGINE_PLUGIN_SLUG', 'storeengine' );
88 define( 'STOREENGINE_SETTINGS_NAME', 'storeengine_settings' );
89 define( 'STOREENGINE_ADDONS_SETTINGS_NAME', 'storeengine_addons' );
90 define( 'STOREENGINE_PAYMENTS_SETTINGS_NAME', 'storeengine_payments_settings' );
91 define( 'STOREENGINE_PLUGIN_ROOT_URI', plugins_url( '/', __FILE__ ) );
92 /** @define "STOREENGINE_ROOT_DIR_PATH" "./" */
93 define( 'STOREENGINE_ROOT_DIR_PATH', plugin_dir_path( __FILE__ ) );
94 /** @define "STOREENGINE_INCLUDES_DIR_PATH" "./includes/" */
95 define( 'STOREENGINE_INCLUDES_DIR_PATH', STOREENGINE_ROOT_DIR_PATH . 'includes/' );
96 define( 'STOREENGINE_ASSETS_DIR_PATH', STOREENGINE_ROOT_DIR_PATH . 'assets/' );
97 define( 'STOREENGINE_ASSETS_URI', STOREENGINE_PLUGIN_ROOT_URI . 'assets/' );
98 define( 'STOREENGINE_ADDONS_DIR_PATH', STOREENGINE_ROOT_DIR_PATH . 'addons/' );
99 define( 'STOREENGINE_LIBRARY_PATH', STOREENGINE_ROOT_DIR_PATH . 'libraries/' );
100 define( 'STOREENGINE_TEMPLATE_DEBUG_MODE', false );
101 /** @define "STOREENGINE_TEMPLATE_PATH" "./templates/" */
102 define( 'STOREENGINE_TEMPLATE_PATH', STOREENGINE_ROOT_DIR_PATH . 'templates/' );
103 define( 'STOREENGINE_BLOCK_TEMPLATES_DIR_PATH', STOREENGINE_ROOT_DIR_PATH . 'templates/block-templates/' );
104
105 $upload_dir = wp_get_upload_dir();
106 /** @define "STOREENGINE_SECURE_UPLOADS_DIR" "./../../uploads/storeengine_uploads" */
107 define( 'STOREENGINE_SECURE_UPLOADS_DIR', $upload_dir['basedir'] . '/storeengine_uploads' );
108 define( 'STOREENGINE_LOGS_DIR', $upload_dir['basedir'] . '/storeengine-logs' );
109 }
110
111 public function log_errors() {
112 $error = error_get_last();
113 $allowed_errors = [ E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR ];
114
115 // Catch only severe errors that halt execution.
116 if ( $error !== null && in_array( $error['type'], $allowed_errors, true ) ) {
117
118 // Map fatal error types to readable names.
119 $error_names = [
120 E_ERROR => 'Fatal Error',
121 E_PARSE => 'Parse Error',
122 E_CORE_ERROR => 'Core Error',
123 E_COMPILE_ERROR => 'Compile Error',
124 E_USER_ERROR => 'User Error',
125 ];
126 $error_type = $error_names[ $error['type'] ] ?? 'Fatal Error';
127 $error_copy = $error;
128 $message = $error_copy['message'];
129 unset( $error_copy['message'] );
130
131 $context = [ 'error' => $error_copy ];
132
133 if ( false !== strpos( $message, 'Stack trace:' ) ) {
134 $segments = explode( 'Stack trace:', $message );
135 $message = str_replace( PHP_EOL, ' ', trim( $segments[0] ) );
136 $backtrace = array_map( 'trim', explode( PHP_EOL, $segments[1] ) );
137
138 $context['backtrace'] = $backtrace;
139 } else {
140 $context['backtrace'] = true;
141 }
142
143 // Format a descriptive title, e.g., Critical Crash: PHP Fatal Error.
144 $title = sprintf( 'Critical Crash: PHP %s', $error_type );
145
146 $content = [
147 'message' => $message,
148 'file' => $error['file'],
149 'line' => $error['line'],
150 'context' => $context,
151 ];
152
153 Logger::log( $title, $content, Logger::CRITICAL, 'system' );
154
155 /**
156 * Action triggered when there are errors during shutdown.
157 *
158 * @since 1.8.0
159 */
160 do_action( 'storeengine_shutdown_error', $error );
161 }
162 }
163
164 /**
165 * When WP has loaded all plugins, trigger the `storeengine_loaded` hook.
166 *
167 * This ensures `storeengine_loaded` is called only after all other plugins
168 * are loaded, to avoid issues caused by plugin directory naming changing
169 */
170 public function on_plugins_loaded() {
171 /**
172 * When WP has loaded all plugins, trigger the storeengine_loaded hook.
173 */
174 do_action( 'storeengine_loaded' );
175 }
176
177 /**
178 * Initialize the plugin
179 *
180 * @return void
181 */
182 public function init_plugin() {
183 //$non_existent_variable->method();
184 /**
185 * Before the plugin initialization.
186 */
187 do_action( 'storeengine/before_init' );
188 StoreEngine\Utils\Caching::init();
189 $this->load_addons();
190 StoreEngine\Payment_Gateways::init();
191 $this->dispatch_hooks();
192 /**
193 * Initialize the plugin.
194 */
195 do_action( 'storeengine_init' );
196 }
197
198 public function dispatch_hooks() {
199 DownloadHandler::init();
200 UrlPresigner::init();
201 StoreEngine\Cli::init();
202 StoreEngine\Hooks::init();
203 StoreEngine\Database::init();
204 StoreEngine\PermalinkRewrite::init();
205 StoreEngine\Shipping\Shipping::init();
206 StoreEngine\API::init();
207 StoreEngine\Ajax::init();
208 StoreEngine\Assets::init();
209 StoreEngine\Shortcode::init();
210 StoreEngine\Integrations::init();
211 StoreEngine\Migration::init();
212 StoreEngine\Backup\BackupManager::init();
213 StoreEngine\Miscellaneous::init();
214 StoreEngine\Schedule::init();
215 StockManager::init();
216 Tax::init();
217
218 if ( is_admin() ) {
219 StoreEngine\Admin::init();
220 }
221
222 StoreEngine\Frontend::init();
223 }
224
225 public function dispatch_post_hooks() {
226 StoreEngine\Post::init();
227 }
228
229 public function load_addons() {
230 StoreEngine\Addons::init();
231 }
232
233 /**
234 * Load global settings.
235 *
236 * @deprecated
237 * @see \StoreEngine\Admin\Settings::load_settings()
238 */
239 public function set_global_settings() {
240 $GLOBALS['storeengine_settings'] = apply_filters( 'storeengine_settings', json_decode( get_option( STOREENGINE_SETTINGS_NAME, '{}' ) ) );
241 $GLOBALS['storeengine_addons'] = json_decode( get_option( STOREENGINE_ADDONS_SETTINGS_NAME, '{}' ) );
242 }
243
244 public function load_dependency(): bool {
245 // Internal Autoload — required; without it nothing else can load.
246 if ( ! self::require_or_notice( STOREENGINE_INCLUDES_DIR_PATH . 'autoload.php', 'StoreEngine' ) ) {
247 return false;
248 }
249
250 // Autoload prefixed / composer packages. Optional — keep the existing
251 // tolerant behavior (don't abort if absent).
252 self::require_or_notice( STOREENGINE_ROOT_DIR_PATH . 'vendor/prefixed/autoload.php', 'StoreEngine', false );
253 self::require_or_notice( STOREENGINE_ROOT_DIR_PATH . 'vendor/autoload.php', 'StoreEngine', false );
254
255 // StoreEngine License Management SDK — loaded here (not by the free
256 // satellite plugins) so the whole ecosystem can share one copy. It is a
257 // version-managed shared library (Action Scheduler pattern): its init.php
258 // registers on `plugins_loaded` pri 0/1, and the highest version across
259 // every active plugin (core, Pro, …) wins. This must run during plugin
260 // load — before `plugins_loaded` fires — which it does, since core is
261 // instantiated at file load. Requiring it here (rather than via composer's
262 // autoload-files) means it works even before `composer install` is run.
263 // The free StoreEngine Payments / Connectors plugins reuse this copy via
264 // the global `se_license_init()` for their automatic store updates.
265 self::require_or_notice( STOREENGINE_ROOT_DIR_PATH . 'vendor/storeengine/wordpress-sdk/init.php', 'StoreEngine', false );
266
267 // Frontend Template and Hooks — hard-required.
268 return self::require_or_notice( STOREENGINE_INCLUDES_DIR_PATH . 'frontend/functions.php', 'StoreEngine' )
269 && self::require_or_notice( STOREENGINE_INCLUDES_DIR_PATH . 'frontend/hooks.php', 'StoreEngine' );
270 }
271
272 /**
273 * Require a bootstrap file, or — if it is missing (e.g. an interrupted
274 * update left the plugin folder incomplete) — register an admin notice and
275 * signal the caller to abort booting instead of fataling with a white
276 * screen. Must not depend on any autoloaded class.
277 *
278 * @param string $path Absolute path to the file to require.
279 * @param string $label Human-readable plugin name for the notice.
280 * @param bool $notify Whether to show an admin notice when missing.
281 * Pass false for optional files.
282 *
283 * @return bool True if required successfully, false if the file is missing.
284 */
285 private static function require_or_notice( string $path, string $label, bool $notify = true ): bool {
286 if ( is_readable( $path ) ) {
287 require_once $path;
288
289 return true;
290 }
291
292 if ( $notify ) {
293 add_action( 'admin_notices', static function () use ( $label ) {
294 echo '<div class="notice notice-error"><p>';
295 echo esc_html( sprintf(
296 /* translators: %s: plugin name. */
297 __( '%s core files are missing or incomplete — please reinstall the plugin.', 'storeengine' ),
298 $label
299 ) );
300 echo '</p></div>';
301 } );
302 }
303
304 return false;
305 }
306
307 /**
308 * Initialize and load the cart functionality.
309 */
310 public function load_cart() {
311 if ( ! did_action( 'storeengine/before_init' ) || doing_action( 'storeengine/before_init' ) ) {
312 /* translators: 1: initialize_session 2: storeengine/before_init */
313 _doing_it_wrong( __FUNCTION__, sprintf( esc_html__( '%1$s should not be called before the %2$s action.', 'storeengine' ), 'storeengine_load_cart', 'storeengine/before_init' ), '1.0.0' );
314
315 return;
316 }
317
318 $this->initialize_cart();
319 }
320
321 /**
322 * Initialize the customer and cart objects and setup customer saving on shutdown.
323 *
324 * Note, storeengine()->customer is session based. Changes to customer data via this property are not persisted to the database automatically.
325 *
326 * @return void
327 */
328 public function initialize_cart() {
329 if ( did_action( 'storeengine/cart/initialized' ) && $this->customer && $this->cart ) {
330 return;
331 }
332
333 if ( ! $this->customer instanceof Customer ) {
334 $this->customer = new Customer( get_current_user_id(), true );
335 }
336
337 if ( ! $this->cart instanceof Cart ) {
338 $this->cart = Cart::init();
339 }
340
341 /**
342 * Fires after cart initialization finished.
343 */
344 do_action( 'storeengine/cart/initialized' );
345 }
346
347 /**
348 * @return ?Cart
349 */
350 public function get_cart(): ?Cart {
351 return $this->cart;
352 }
353
354 /**
355 * @return ?Customer
356 */
357 public function get_customer(): ?Customer {
358 return $this->customer;
359 }
360
361 /**
362 * Get queue instance.
363 *
364 * @return ActionQueue
365 * @throws StoreEngineException
366 */
367 public function queue(): ActionQueue {
368 return ActionQueue::get_instance();
369 }
370
371 public function activate() {
372 StoreEngine\Installer::install();
373 }
374
375 public function deactivate() {
376 StoreEngine\Installer::uninstall();
377 }
378
379 public function activated_redirect( $plugin, $network_wide = null ) {
380 if ( $network_wide || class_exists( \WP_CLI::class, false ) || STOREENGINE_PLUGIN_BASENAME !== $plugin ) {
381 return;
382 }
383
384 if ( 'yes' === get_option( 'storeengine_has_redirect_to_setup_wizard', 'no' ) ) {
385 return;
386 }
387
388 update_option( 'storeengine_has_redirect_to_setup_wizard', 'yes', false );
389 wp_safe_redirect( admin_url( 'admin.php?page=storeengine-setup' ) );
390 exit;
391 }
392 }
393
394 /**
395 * Initializes the main plugin
396 *
397 * @return StoreEngine
398 */
399 function storeengine(): StoreEngine {
400 return StoreEngine::init();
401 }
402
403 /**
404 * Initializes the main plugin
405 *
406 * @return StoreEngine
407 * @deprecated in favor of storeengine()
408 * @see storeengine()
409 */
410 function storeengine_start(): StoreEngine {
411 return storeengine();
412 }
413
414 // Plugin Start
415 storeengine();
416