PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 1.9.1
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v1.9.1
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 / includes / installer.php

installer.php in StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More 1.9.1, at includes/installer.php

269 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace StoreEngine;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit; // Exit if accessed directly.
7 }
8
9 use StoreEngine\Admin\Notices;
10 use StoreEngine\Admin\Settings;
11 use StoreEngine\Classes\Role;
12 use StoreEngine\Utils\Helper;
13
14 class Installer {
15 protected $storeengine_version;
16
17 public function __construct() {
18 $this->storeengine_version = get_option( 'storeengine_version' );
19 }
20
21 public static function init() {
22 add_action( 'init', [ __CLASS__, 'check_version' ], 5 );
23 }
24
25 /**
26 * Check version & run installer if needed.
27 *
28 * @since 1.6.4
29 * @return void
30 */
31 public static function check_version() {
32 $requires_update = version_compare( get_option( 'storeengine_version' ), STOREENGINE_VERSION, '<' );
33 if ( ! defined( 'IFRAME_REQUEST' ) && $requires_update ) {
34 define( 'STOREENGINE_UPDATING', true );
35 // Run the installer.
36 self::install();
37
38 /**
39 * Run after StoreEngine has been updated.
40 *
41 * @since 1.6.4
42 */
43 do_action( 'storeengine/updated' );
44 }
45 }
46
47 public static function install() {
48 if ( ! is_blog_installed() ) {
49 return;
50 }
51
52 // Check if we are not already running this routine.
53 if ( 'yes' === get_transient( 'storeengine_installing' ) ) {
54 return;
55 }
56
57 // If we made it till here nothing is running yet, lets set the transient now.
58 set_transient( 'storeengine_installing', 'yes', MINUTE_IN_SECONDS * 10 );
59
60 define( 'STOREENGINE_INSTALLING', true );
61
62 global $wpdb;
63 $wpdb->hide_errors();
64
65 try {
66 Database::init()->wpdb_table_fix();
67 Notices::remove_all_notices();
68 Database::create_initial_custom_table();
69 Settings::save_settings();
70 self::add_role();
71 // Create files.
72 self::create_base_secure_directory();
73 // Need for flush rewrite rules.
74 PermalinkRewrite::init();
75 Database::init()->register_product_post_type();
76
77 if ( ! self::is_new_install() && 'yes' !== get_option( 'storeengine_has_redirect_to_setup_wizard', 'no' ) ) {
78 // Don't redirect old users to setup-wizard upon update.
79 update_option( 'storeengine_has_redirect_to_setup_wizard', 'yes', false );
80 }
81
82 update_option( 'storeengine_version', STOREENGINE_VERSION );
83 } catch ( \Exception $e ) {
84 // NoOp.
85 Helper::log_error( $e );
86 } finally {
87 delete_transient( 'storeengine_installing' );
88 }
89
90 if ( ! get_option( 'storeengine_first_install_time' ) ) {
91 add_option( 'storeengine_first_install_time', Helper::get_time() );
92 }
93
94 // Force a flush of rewrite rules even if the corresponding hook isn't initialized yet.
95 if ( ! has_action( 'storeengine/flush_rewrite_rules' ) ) {
96 flush_rewrite_rules();
97 }
98
99 /**
100 * Flush the rewrite rules after install or update.
101 */
102 do_action( 'storeengine/flush_rewrite_rules' );
103
104 /**
105 * Run after StoreEngine has been installed or updated.
106 *
107 * @since 1.6.4
108 */
109 do_action( 'storeengine/installed' );
110 }
111
112 /**
113 * Is this a brand-new StoreEngine installation?
114 *
115 * A brand-new installation has no version yet. Also treat empty installations as 'new'.
116 *
117 * @return boolean
118 */
119 public static function is_new_install(): bool {
120 return
121 is_null( get_option( 'storeengine_version', null ) ) ||
122 is_null( get_option( 'storeengine_first_install_time', null ) ) ||
123 (
124 ! Helper::get_settings( 'shop_page' ) &&
125 0 === array_sum( (array) wp_count_posts( Helper::PRODUCT_POST_TYPE ) )
126 );
127 }
128
129 public static function add_role() {
130 // customer role
131 Role::add_customer_role();
132 // shop manager role
133 Role::add_shop_manager_role();
134 }
135
136 /**
137 * Create files/directories.
138 */
139 public static function create_base_secure_directory() {
140 // Install files and folders for uploading files and prevent hotlinking.
141 // Directory is restricted and downloads must be proxied via script.
142 $htaccess = '<IfModule mod_authz_core.c>' . PHP_EOL;
143 $htaccess .= "\tRequire all denied" . PHP_EOL;
144 $htaccess .= '</IfModule>' . PHP_EOL;
145 $htaccess .= '<IfModule !mod_authz_core.c>' . PHP_EOL;
146 $htaccess .= "\tDeny from all" . PHP_EOL;
147 $htaccess .= '</IfModule>';
148
149 self::create_uploads_upload_directory_files( [
150 [
151 'base' => STOREENGINE_SECURE_UPLOADS_DIR,
152 'file' => 'index.html', // Empty index, so server does not output auto-generated directory index.
153 'content' => '',
154 ],
155 [
156 'base' => STOREENGINE_SECURE_UPLOADS_DIR,
157 'file' => '.htaccess',
158 'content' => $htaccess,
159 ],
160 [
161 'base' => STOREENGINE_LOGS_DIR,
162 'file' => 'index.html',
163 'content' => '',
164 ],
165 [
166 'base' => STOREENGINE_LOGS_DIR,
167 'file' => '.htaccess',
168 'content' => $htaccess,
169 ],
170 ] );
171
172 // @TODO (In a separate function:private) Create a placeholder image in the media library (STOREENGINE_ASSETS_URI . images/thumbnail-placeholder.png).
173 // Add settings for user to change placeholder image.
174 // @TODO Add image sizes for gallery, preview & thumbnails.
175 // Maybe add settings for user to change image sizes
176 // If image sizes changes or theme switched regenerate thumbnails.
177 }
178
179 public static function create_uploads_upload_directory_files( array $config ) {
180 $upload_dir = wp_get_upload_dir();
181
182 foreach ( $config as $file ) {
183 $file = wp_parse_args( $file, [
184 'base' => '',
185 'file' => '',
186 'content' => '',
187 ] );
188
189 if ( empty( $file['base'] ) ) {
190 continue;
191 }
192
193 if ( ! str_starts_with( $file['base'], $upload_dir['basedir'] ) ) {
194 // Maybe out-of wp-content/uploads.
195 continue;
196 }
197
198 $file['file'] = ltrim( rtrim( $file['file'], '/\\' ), '/\\' );
199
200 // Check if file not exists first. If the file exists, the directory is already created.
201 if ( ! file_exists( trailingslashit( $file['base'] ) . $file['file'] ) && wp_mkdir_p( $file['base'] ) && $file['file'] ) {
202 $file_handle = @fopen( trailingslashit( $file['base'] ) . $file['file'], 'wb' ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_read_fopen, WordPress.WP.AlternativeFunctions.file_system_operations_fopen
203
204 if ( $file_handle ) {
205 fwrite( $file_handle, $file['content'] ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite, WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
206 fclose( $file_handle ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose, WordPress.WP.AlternativeFunctions.file_system_operations_fclose
207 }
208 }
209 }
210 }
211
212 public static function uninstall() {
213 // Cancel every action this plugin (and its addons) may have scheduled.
214 // Leaving them in the queue causes orphaned actions to fire forever
215 // against handlers that no longer exist.
216 foreach ( self::get_known_scheduled_action_hooks() as $hook ) {
217 as_unschedule_all_actions( $hook );
218 }
219
220 flush_rewrite_rules();
221 }
222
223 /**
224 * Every Action Scheduler hook owned by StoreEngine core + bundled addons.
225 * Kept in one place so the "Reset Action Scheduler" admin tool and the
226 * uninstall hook stay in sync.
227 *
228 * @return string[]
229 */
230 public static function get_known_scheduled_action_hooks(): array {
231 return [
232 // Core.
233 'storeengine/geolocation/maxmind/db-update',
234 'storeengine/logs/auto_cleanup',
235 'storeengine/store_product_lookup',
236 'storeengine/remove_product_lookup_data',
237
238 // Webhooks addon.
239 'storeengine/webhooks/async_delivery',
240
241 // CSV addon.
242 'storeengine/csv/clean_tmp_csv',
243
244 // Invoice addon.
245 'storeengine/mail/clean_tmp_invoices',
246
247 // Multi-currency addon.
248 'storeengine/multi_currency/refresh_rates',
249
250 // Subscription addon.
251 'storeengine/subscription/start',
252 'storeengine/subscription/renewal',
253 'storeengine/subscription/scheduled_payment',
254 'storeengine/subscription/schedule_payment_retry',
255 'storeengine/subscription/schedule_trial_end',
256 'storeengine/subscription/schedule_expiration',
257 'storeengine/subscription/schedule_end_of_prepaid_term',
258
259 // Deprecated subscription hooks (kept for cleanup of legacy installs).
260 'storeengine_subscription_renewal',
261 'storeengine_create_renewal_order_schedule',
262
263 // StoreEngine Pro — license management addon.
264 'storeengine_pro/license/update_top_product_cache',
265 'storeengine_pro/license/update_event_cc',
266 ];
267 }
268 }
269