PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 2.2.0
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v2.2.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 / includes / ajax / tools.php

tools.php in StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More 2.2.0, at includes/ajax/tools.php

197 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace StoreEngine\Ajax;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit;
7 }
8
9 use StoreEngine\Addons\Affiliate\Affiliate;
10 use StoreEngine\Addons\Membership\Membership;
11 use StoreEngine\Admin\ScheduledActionsTool;
12 use StoreEngine\Classes\AbstractAjaxHandler;
13 use StoreEngine\Utils\Helper;
14
15 class Tools extends AbstractAjaxHandler {
16 public function __construct() {
17 $this->actions = [
18 'fetch_storeengine_status' => [
19 'capability' => 'manage_options',
20 'callback' => [ $this, 'fetch_storeengine_status' ],
21 ],
22 'fetch_storeengine_pages' => [
23 'capability' => 'manage_options',
24 'callback' => [ $this, 'fetch_storeengine_pages' ],
25 ],
26 'regenerate_storeengine_pages' => [
27 'capability' => 'manage_options',
28 'callback' => [ $this, 'regenerate_storeengine_pages' ],
29 ],
30 'fetch_storeengine_scheduled_actions' => [
31 'capability' => 'manage_options',
32 'callback' => [ $this, 'fetch_storeengine_scheduled_actions' ],
33 ],
34 'reset_storeengine_scheduled_actions' => [
35 'capability' => 'manage_options',
36 'callback' => [ $this, 'reset_storeengine_scheduled_actions' ],
37 'fields' => [
38 'hooks' => self::STR_ARR,
39 'include_logs' => self::BOOLEAN,
40 'cleanup_tools' => self::STR_ARR,
41 ],
42 ],
43 ];
44 }
45
46 /**
47 * Registry of "data cleanup" tools surfaced under the Action Scheduler tab.
48 * Addons can attach entries via the `storeengine/tools/data_cleanup_tools`
49 * filter — each entry pairs UI metadata with a server-side callback that
50 * performs the cleanup. Used when cancelling pending actions alone is not
51 * enough (e.g. also truncating addon-owned tables).
52 *
53 * @return array<int, array{id:string, label:string, description:string, confirm?:string, callback:callable}>
54 */
55 public static function get_data_cleanup_tools(): array {
56 return array_values( array_filter(
57 (array) apply_filters( 'storeengine/tools/data_cleanup_tools', [] ),
58 static fn( $t ) => is_array( $t )
59 && ! empty( $t['id'] )
60 && ! empty( $t['label'] )
61 && ! empty( $t['callback'] )
62 && is_callable( $t['callback'] )
63 ) );
64 }
65
66 protected function fetch_storeengine_status() {
67 $tools = new \StoreEngine\Classes\Tools();
68
69 wp_send_json_success( [
70 'wordpress' => $tools->get_wordpress_environment_status(),
71 'server' => $tools->get_server_environment_status(),
72 ] );
73 }
74
75 protected function fetch_storeengine_pages() {
76 global $storeengine_settings;
77 $pages = apply_filters( 'storeengine/settings/tools/pages', [
78 'shop_page' => __( 'Store Shop', 'storeengine' ),
79 'cart_page' => __( 'Store Cart', 'storeengine' ),
80 'checkout_page' => __( 'Store Checkout', 'storeengine' ),
81 'thankyou_page' => __( 'Store Thank You', 'storeengine' ),
82 'dashboard_page' => __( 'Store Dashboard', 'storeengine' ),
83 ] );
84
85 $response = [];
86 $idx = 0;
87 foreach ( $pages as $key => $label ) {
88 $page = Helper::get_settings( $key );
89 $page = $page ? get_post( $page ) : false;
90 $response[] = [
91 'key' => $key,
92 'index' => ++$idx,
93 'ID' => $page ? $page->ID : null,
94 'post_title' => $page ? $page->post_title : $label,
95 'post_name' => $page ? $page->post_name : null,
96 'post_status' => $page ? $page->post_status : null,
97 'permalink' => $page ? get_permalink( $page ) : null,
98 'edit_link' => $page && current_user_can( 'manage_options' ) ? get_edit_post_link( $page ) : null,
99 ];
100 }
101
102 wp_send_json_success( $response );
103 }
104
105 protected function regenerate_storeengine_pages() {
106 Helper::create_initial_pages();
107 wp_send_json_success();
108 }
109
110 /**
111 * Return per-hook pending/failed counts for the StoreEngine Action
112 * Scheduler queue. Used by the "Action Scheduler" tab in Tools.
113 */
114 protected function fetch_storeengine_scheduled_actions(): array {
115 $rows = ScheduledActionsTool::get_hook_counts();
116 $total = 0;
117 foreach ( $rows as $row ) {
118 $total += $row['pending'];
119 }
120
121 // Strip callbacks before sending to the client — closures and array
122 // callbacks aren't safe to JSON-serialise and the UI doesn't need them.
123 $cleanup_tools = array_map( static function ( array $tool ): array {
124 return [
125 'id' => (string) $tool['id'],
126 'label' => (string) $tool['label'],
127 'description' => (string) ( $tool['description'] ?? '' ),
128 'confirm' => (string) ( $tool['confirm'] ?? '' ),
129 ];
130 }, self::get_data_cleanup_tools() );
131
132 return [
133 'rows' => $rows,
134 'total' => $total,
135 'logs_table' => $GLOBALS['wpdb']->prefix . 'actionscheduler_logs',
136 'known_hooks' => ScheduledActionsTool::get_known_hooks(),
137 'data_cleanup_tools' => $cleanup_tools,
138 ];
139 }
140
141 /**
142 * Cancel pending/failed Action Scheduler events for the requested hooks,
143 * optionally truncate AS logs, and optionally run one or more addon-supplied
144 * data cleanup callbacks (e.g. truncating an addon-owned records table).
145 * All three actions are handled in a single request so the UI can update
146 * in one round-trip.
147 *
148 * @param array{hooks?: string[], include_logs?: bool, cleanup_tools?: string[]} $payload
149 */
150 protected function reset_storeengine_scheduled_actions( array $payload ): array {
151 $requested = isset( $payload['hooks'] ) && is_array( $payload['hooks'] ) ? $payload['hooks'] : [];
152 $tools_requested = isset( $payload['cleanup_tools'] ) && is_array( $payload['cleanup_tools'] ) ? $payload['cleanup_tools'] : [];
153 $known = array_flip( ScheduledActionsTool::get_known_hooks() );
154 $cancelled = 0;
155 $cleared = [];
156
157 foreach ( $requested as $hook ) {
158 if ( ! isset( $known[ $hook ] ) ) {
159 continue;
160 }
161 $n = ScheduledActionsTool::cancel_hook( $hook );
162 $cancelled += $n;
163 $cleared[] = [ 'hook' => $hook, 'count' => $n ];
164 }
165
166 if ( ! empty( $payload['include_logs'] ) ) {
167 global $wpdb;
168 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange
169 $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}actionscheduler_logs" );
170 }
171
172 // Run requested data-cleanup tool callbacks (e.g. addon table purges).
173 // Tools are looked up by id against the filter-registered registry so
174 // the client can't invoke arbitrary callables.
175 $tool_results = [];
176 if ( $tools_requested ) {
177 $available = [];
178 foreach ( self::get_data_cleanup_tools() as $tool ) {
179 $available[ $tool['id'] ] = $tool;
180 }
181 foreach ( $tools_requested as $tool_id ) {
182 if ( ! isset( $available[ $tool_id ] ) ) {
183 continue;
184 }
185 $tool_results[ $tool_id ] = (array) call_user_func( $available[ $tool_id ]['callback'] );
186 }
187 }
188
189 return [
190 'cancelled' => $cancelled,
191 'cleared' => $cleared,
192 'tool_results' => $tool_results,
193 'rows' => ScheduledActionsTool::get_hook_counts(),
194 ];
195 }
196 }
197