PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 2.0.0
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v2.0.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.0.0, at storeengine.php

404 lines 12.3 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.0.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.0.0' );
84 define( 'STOREENGINE_DB_VERSION', '1.3' );
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 // Frontend Template and Hooks — hard-required.
256 return self::require_or_notice( STOREENGINE_INCLUDES_DIR_PATH . 'frontend/functions.php', 'StoreEngine' )
257 && self::require_or_notice( STOREENGINE_INCLUDES_DIR_PATH . 'frontend/hooks.php', 'StoreEngine' );
258 }
259
260 /**
261 * Require a bootstrap file, or — if it is missing (e.g. an interrupted
262 * update left the plugin folder incomplete) — register an admin notice and
263 * signal the caller to abort booting instead of fataling with a white
264 * screen. Must not depend on any autoloaded class.
265 *
266 * @param string $path Absolute path to the file to require.
267 * @param string $label Human-readable plugin name for the notice.
268 * @param bool $notify Whether to show an admin notice when missing.
269 * Pass false for optional files.
270 *
271 * @return bool True if required successfully, false if the file is missing.
272 */
273 private static function require_or_notice( string $path, string $label, bool $notify = true ): bool {
274 if ( is_readable( $path ) ) {
275 require_once $path;
276
277 return true;
278 }
279
280 if ( $notify ) {
281 add_action( 'admin_notices', static function () use ( $label ) {
282 echo '<div class="notice notice-error"><p>';
283 echo esc_html( sprintf(
284 /* translators: %s: plugin name. */
285 __( '%s core files are missing or incomplete — please reinstall the plugin.', 'storeengine' ),
286 $label
287 ) );
288 echo '</p></div>';
289 } );
290 }
291
292 return false;
293 }
294
295 /**
296 * Initialize and load the cart functionality.
297 */
298 public function load_cart() {
299 if ( ! did_action( 'storeengine/before_init' ) || doing_action( 'storeengine/before_init' ) ) {
300 /* translators: 1: initialize_session 2: storeengine/before_init */
301 _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' );
302
303 return;
304 }
305
306 $this->initialize_cart();
307 }
308
309 /**
310 * Initialize the customer and cart objects and setup customer saving on shutdown.
311 *
312 * Note, storeengine()->customer is session based. Changes to customer data via this property are not persisted to the database automatically.
313 *
314 * @return void
315 */
316 public function initialize_cart() {
317 if ( did_action( 'storeengine/cart/initialized' ) && $this->customer && $this->cart ) {
318 return;
319 }
320
321 if ( ! $this->customer instanceof Customer ) {
322 $this->customer = new Customer( get_current_user_id(), true );
323 }
324
325 if ( ! $this->cart instanceof Cart ) {
326 $this->cart = Cart::init();
327 }
328
329 /**
330 * Fires after cart initialization finished.
331 */
332 do_action( 'storeengine/cart/initialized' );
333 }
334
335 /**
336 * @return ?Cart
337 */
338 public function get_cart(): ?Cart {
339 return $this->cart;
340 }
341
342 /**
343 * @return ?Customer
344 */
345 public function get_customer(): ?Customer {
346 return $this->customer;
347 }
348
349 /**
350 * Get queue instance.
351 *
352 * @return ActionQueue
353 * @throws StoreEngineException
354 */
355 public function queue(): ActionQueue {
356 return ActionQueue::get_instance();
357 }
358
359 public function activate() {
360 StoreEngine\Installer::install();
361 }
362
363 public function deactivate() {
364 StoreEngine\Installer::uninstall();
365 }
366
367 public function activated_redirect( $plugin, $network_wide = null ) {
368 if ( $network_wide || class_exists( \WP_CLI::class, false ) || STOREENGINE_PLUGIN_BASENAME !== $plugin ) {
369 return;
370 }
371
372 if ( 'yes' === get_option( 'storeengine_has_redirect_to_setup_wizard', 'no' ) ) {
373 return;
374 }
375
376 update_option( 'storeengine_has_redirect_to_setup_wizard', 'yes', false );
377 wp_safe_redirect( admin_url( 'admin.php?page=storeengine-setup' ) );
378 exit;
379 }
380 }
381
382 /**
383 * Initializes the main plugin
384 *
385 * @return StoreEngine
386 */
387 function storeengine(): StoreEngine {
388 return StoreEngine::init();
389 }
390
391 /**
392 * Initializes the main plugin
393 *
394 * @return StoreEngine
395 * @deprecated in favor of storeengine()
396 * @see storeengine()
397 */
398 function storeengine_start(): StoreEngine {
399 return storeengine();
400 }
401
402 // Plugin Start
403 storeengine();
404