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 / api / logs.php

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

294 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace StoreEngine\API;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 use WP_REST_Controller;
9 use WP_REST_Request;
10 use WP_REST_Server;
11 use WP_Error;
12 use StoreEngine\Utils\Helper;
13 use StoreEngine\Classes\LogItem;
14 use StoreEngine\Classes\LogItemCollection;
15
16 class Logs extends WP_REST_Controller {
17
18 /**
19 * Constructor.
20 */
21 public function __construct() {
22 $this->namespace = STOREENGINE_PLUGIN_SLUG . '/v1';
23 $this->rest_base = 'logs';
24 }
25
26 /**
27 * Init the API class.
28 */
29 public static function init() {
30 $self = new self();
31 add_action( 'rest_api_init',[ $self, 'register_routes' ] );
32 }
33
34 /**
35 * Register the routes for the objects of the controller.
36 */
37 public function register_routes() {
38 // Route to fetch and delete logs.
39 register_rest_route( $this->namespace, '/' . $this->rest_base, [
40 [
41 'methods' => WP_REST_Server::READABLE,
42 'callback' => [ $this, 'get_items' ],
43 // 'permission_callback' =>[ $this, 'permissions_check' ],
44 'permission_callback' => '__return_true',
45 'args' => $this->get_collection_params(),
46 ],
47 [
48 'methods' => WP_REST_Server::DELETABLE,
49 'callback' => [ $this, 'delete_items' ],
50 'permission_callback' => [ $this, 'permissions_check' ],
51 'args' => [
52 'ids' => [
53 'required' => true,
54 'type' => 'array',
55 'items' => [
56 'type' => 'integer',
57 ],
58 ],
59 ],
60 ],
61 ] );
62
63 // Route to get and save log cleanup settings.
64 register_rest_route( $this->namespace, '/' . $this->rest_base . '/settings', [
65 [
66 'methods' => WP_REST_Server::READABLE,
67 'callback' => [ $this, 'get_settings' ],
68 'permission_callback' => [ $this, 'permissions_check' ],
69 ],
70 [
71 'methods' => WP_REST_Server::CREATABLE,
72 'callback' => [ $this, 'save_settings' ],
73 'permission_callback' => [ $this, 'permissions_check' ],
74 'args' => $this->get_settings_params(),
75 ],
76 ] );
77 }
78
79 /**
80 * Get a collection of logs.
81 *
82 * @param WP_REST_Request $request Full data about the request.
83 * @return \WP_REST_Response|\WP_Error
84 */
85 public function get_items( $request ) {
86 $args =[
87 'page' => (int) $request->get_param( 'page' ),
88 'per_page' => (int) $request->get_param( 'per_page' ),
89 'where' => []
90 ];
91
92 if ( $status = $request->get_param( 'status' ) ) {
93 $args['where'][] =[ 'key' => 'status', 'value' => $status ];
94 }
95
96 if ( $module = $request->get_param( 'module' ) ) {
97 $args['where'][] =[ 'key' => 'module', 'value' => $module ];
98 }
99
100 if ( $search = $request->get_param( 'search' ) ) {
101 $args['where'][] =[ 'key' => 'title', 'value' => $search, 'compare' => 'LIKE' ];
102 }
103
104 // Best-effort entity filters: the storeengine_logs.content column holds a
105 // JSON blob (when Logger::log was called with an array). Most relevant
106 // modules — checkout, gateways, abandoned-cart-email — pass order_id /
107 // customer_id / abandoned_cart_id keys. Match via LIKE so per-entity
108 // detail pages can surface "anything we logged about this order/customer/cart"
109 // without us migrating every Logger call site to write structured columns.
110 // Brittle if log writers stop including these keys, but acceptable as a
111 // best-effort view (the canonical audit still lives in storeengine_email_log).
112 if ( $order_id = (int) $request->get_param( 'order_id' ) ) {
113 $args['where'][] = [
114 'key' => 'content',
115 'value' => '%"order_id":' . $order_id . '%',
116 'compare' => 'LIKE',
117 ];
118 }
119
120 if ( $customer_id = (int) $request->get_param( 'customer_id' ) ) {
121 $args['where'][] = [
122 'key' => 'content',
123 'value' => '%"customer_id":' . $customer_id . '%',
124 'compare' => 'LIKE',
125 ];
126 }
127
128 if ( $abc_id = (int) $request->get_param( 'abandoned_cart_id' ) ) {
129 $args['where'][] = [
130 'key' => 'content',
131 'value' => '%"abandoned_cart":' . $abc_id . '%',
132 'compare' => 'LIKE',
133 ];
134 }
135
136 $collection = new LogItemCollection( $args );
137
138 $results = $collection->get_results();
139 $data =[];
140
141 foreach ( $results as $log ) {
142 $data[] = $log->get_data();
143 }
144
145 $response = rest_ensure_response( $data );
146 $response->header( 'X-WP-Total', (string) $collection->get_found_results() );
147 $response->header( 'X-WP-TotalPages', (string) $collection->get_max_num_pages() );
148
149 return $response;
150 }
151
152 /**
153 * Delete single or multiple logs.
154 *
155 * @param WP_REST_Request $request Full data about the request.
156 * @return \WP_REST_Response|\WP_Error
157 */
158 public function delete_items( $request ) {
159 $ids = $request->get_param( 'ids' );
160
161 if ( empty( $ids ) || ! is_array( $ids ) ) {
162 return new WP_Error( 'invalid_log_ids', __( 'Invalid or empty IDs provided.', 'storeengine' ), [ 'status' => 400 ] );
163 }
164
165 $query = new LogItemCollection( [
166 'per_page' => - 1,
167 'where' => [
168 'key' => 'id',
169 'value' => array_filter( array_unique( array_map( 'absint', $ids ) ) ),
170 'compare' => 'IN',
171 ]
172 ] );
173
174 $deleted = [];
175
176 while ( $query->have_results() ) {
177 $query->the_result();
178 global $log;
179
180 try {
181 $id = $log->get_id();
182 $log->delete( true );
183 $deleted[] = $id;
184 } catch ( \Throwable $e ) {
185 // No op.
186 }
187 }
188
189 $deleted_count = count( $deleted );
190
191 return rest_ensure_response( [
192 'message' => sprintf(
193 // translators: %d is the number of deleted logs.
194 _n( '%d log deleted successfully.', '%d logs deleted successfully.', $deleted_count, 'storeengine' ),
195 $deleted_count
196 ),
197 'deleted' => $deleted,
198 ] );
199 }
200
201 /**
202 * Retrieve log cleanup settings from the database.
203 *
204 * @param WP_REST_Request $request Full data about the request.
205 * @return \WP_REST_Response|\WP_Error
206 */
207 public function get_settings( $request ) {
208 $settings = get_option( 'storeengine_log_settings',[
209 'retention_days' => 30,
210 'cleanup_statuses' => [ 'success' ]
211 ] );
212
213 return rest_ensure_response( $settings );
214 }
215
216 /**
217 * Save log cleanup settings to the database.
218 *
219 * @param WP_REST_Request $request Full data about the request.
220 * @return \WP_REST_Response|\WP_Error
221 */
222 public function save_settings( $request ) {
223 $retention_days = (int) $request->get_param( 'retention_days' );
224 $cleanup_statuses = $request->get_param( 'cleanup_statuses' );
225
226 // Security check: Fallback to an empty array if not a valid array.
227 if ( ! is_array( $cleanup_statuses ) ) {
228 $cleanup_statuses = [];
229 }
230
231 $settings =[
232 'retention_days' => $retention_days,
233 'cleanup_statuses' => array_map( 'sanitize_text_field', $cleanup_statuses )
234 ];
235
236 update_option( 'storeengine_log_settings', $settings );
237
238 return rest_ensure_response([
239 'message' => __( 'Log settings saved successfully.', 'storeengine' ),
240 'settings' => $settings
241 ] );
242 }
243
244 /**
245 * Check if a given request has access to the logs.
246 *
247 * @param WP_REST_Request $request Full data about the request.
248 * @return bool|\WP_Error
249 */
250 public function permissions_check( $request ) {
251 return Helper::check_rest_user_cap( 'manage_options' );
252 }
253
254 /**
255 * Get the query params for collections.
256 *
257 * @return array
258 */
259 public function get_collection_params(): array {
260 return [
261 'page' => [ 'default' => 1, 'sanitize_callback' => 'absint' ],
262 'per_page' => [ 'default' => 20, 'sanitize_callback' => 'absint' ],
263 'status' => [ 'sanitize_callback' => 'sanitize_text_field' ],
264 'module' => [ 'sanitize_callback' => 'sanitize_text_field' ],
265 'search' => [ 'sanitize_callback' => 'sanitize_text_field' ],
266 'order_id' => [ 'sanitize_callback' => 'absint' ],
267 'customer_id' => [ 'sanitize_callback' => 'absint' ],
268 'abandoned_cart_id' => [ 'sanitize_callback' => 'absint' ],
269 ];
270 }
271
272 /**
273 * Get the validation parameters for saving settings.
274 *
275 * @return array
276 */
277 public function get_settings_params(): array {
278 return [
279 'retention_days' =>[
280 'required' => true,
281 'type' => 'integer',
282 'sanitize_callback' => 'absint'
283 ],
284 'cleanup_statuses' =>[
285 'required' => true,
286 'type' => 'array',
287 'items' =>[
288 'type' => 'string'
289 ]
290 ]
291 ];
292 }
293 }
294