PluginProbe
WowAddons – Product Addons and Product Options With Custom Fields / trunk
WowAddons – Product Addons and Product Options With Custom Fields vtrunk
1.7.2 1.7.1 1.7.0 1.6.21 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.5.10 1.5.11 1.5.2 1.5.3 1.5.4 1.5.5 All 57 releases
product-addons / includes / class-analytics.php

class-analytics.php in WowAddons – Product Addons and Product Options With Custom Fields trunk, at includes/class-analytics.php

533 lines 14.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignore
2 /**
3 * Initialization Action.
4 *
5 * @package PRAD
6 * @since 1.0.0
7 */
8 namespace PRAD\Includes;
9
10 defined( 'ABSPATH' ) || exit;
11
12 /**
13 * Initialization class.
14 */
15 class Analytics {
16
17 /**
18 * Setup class.
19 *
20 * @since v.1.0.0
21 */
22 public function __construct() {
23 register_activation_hook( PRAD_PATH . 'product-addons.php', array( $this, 'plugin_activation_hook' ) );
24 add_action( 'prad_update_stats_table_data', array( $this, 'update_stats_table' ), 10, 3 );
25 }
26
27 /**
28 * Redirect After Active Plugin
29 *
30 * @since v.1.0.0
31 *
32 * @param string $plugin Plugin name.
33 *
34 * @return void
35 */
36 public function plugin_activation_hook( $plugin ) { // phpcs:ignore
37 global $wpdb;
38 $wpdb->hide_errors();
39 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
40
41 $this->create_stats_table();
42 $this->create_stats_graph_table();
43 $this->handle_default_option_creations();
44 }
45
46 /**
47 * Handles the creation of default options for the plugin.
48 *
49 * Checks whether the default options have already been created by verifying
50 * the `prad_addons_default_option_created` option. If the option exists,
51 * the function returns early and no further action is taken.
52 *
53 * @return void
54 */
55 public function handle_default_option_creations() {
56 $exists = get_option( 'prad_addons_default_option_created', false );
57 if ( $exists ) {
58 return;
59 }
60 $dummy_content = array(
61 array(
62 'title' => 'Delicious HandMade Pizza',
63 'content' => array(
64 array(
65 'type' => 'checkbox',
66 'blockid' => 'm0tx-pwu08v',
67 'label' => 'Toppings',
68 'desc' => '',
69 'columns' => '2',
70 'enableCount' => false,
71 'hide' => false,
72 'required' => false,
73 'min' => 1,
74 'max' => 100,
75 'minSelect' => '',
76 'maxSelect' => '',
77 'pricePosition' => 'with_option',
78 '_options' => array(
79 array(
80 'value' => 'Olives',
81 'type' => 'fixed',
82 'regular' => '2',
83 'sale' => '',
84 ),
85 array(
86 'value' => 'Mushrooms',
87 'type' => 'fixed',
88 'regular' => '2',
89 'sale' => '',
90 ),
91 array(
92 'value' => 'Pepperoni',
93 'type' => 'fixed',
94 'regular' => '2',
95 'sale' => '',
96 ),
97 array(
98 'value' => 'Chicken',
99 'type' => 'fixed',
100 'regular' => '3',
101 'sale' => '10',
102 ),
103 ),
104 'class' => '',
105 'id' => '',
106 'defval' => array( 3, 2 ),
107 ),
108 array(
109 'type' => 'checkbox',
110 'blockid' => 'mbt7-iizxj3',
111 'label' => 'Dipping Sauce Add-ons',
112 'desc' => '',
113 'columns' => '1',
114 'enableCount' => true,
115 'hide' => false,
116 'required' => false,
117 'min' => 1,
118 'max' => 100,
119 'minSelect' => '',
120 'maxSelect' => '',
121 'pricePosition' => 'with_option',
122 '_options' => array(
123 array(
124 'value' => 'Tomato Sauce',
125 'type' => 'no_cost',
126 'regular' => '',
127 'sale' => '',
128 ),
129 array(
130 'value' => 'Spicy Marinara',
131 'type' => 'per_unit',
132 'regular' => '1',
133 'sale' => '',
134 ),
135 array(
136 'value' => 'Ranch',
137 'type' => 'per_unit',
138 'regular' => '2',
139 'sale' => '',
140 ),
141 ),
142 'class' => '',
143 'id' => '',
144 'defval' => array( 1, 2 ),
145 ),
146 array(
147 'type' => 'button',
148 'blockid' => 'mcw4-d1i4ws',
149 'label' => 'Spice Level',
150 'desc' => '',
151 'multiple' => false,
152 'hide' => false,
153 'required' => false,
154 'vertical' => false,
155 '_options' => array(
156 array(
157 'value' => 'Regular',
158 'type' => 'no_cost',
159 'regular' => '8',
160 'sale' => '',
161 ),
162 array(
163 'value' => 'Medium',
164 'type' => 'no_cost',
165 'regular' => '6',
166 'sale' => '',
167 ),
168 array(
169 'value' => 'Extreme',
170 'type' => 'no_cost',
171 'regular' => '3',
172 'sale' => '',
173 ),
174 ),
175 'class' => '',
176 'id' => '',
177 'defval' => array( 0 ),
178 ),
179 array(
180 'type' => 'range',
181 'blockid' => 'm9uz-kt4i55',
182 'label' => 'Crust Thickness',
183 '_options' => array(
184 array(
185 'type' => 'no_cost',
186 'regular' => '2',
187 'sale' => '',
188 ),
189 ),
190 'min' => 1,
191 'max' => '20',
192 'value' => '3',
193 'step' => 1,
194 'class' => '',
195 'id' => '',
196 'hide' => false,
197 'required' => false,
198 ),
199 ),
200
201 ),
202 array(
203 'title' => 'Buttercream Bluff Cake',
204 'content' => array(
205 array(
206 'type' => 'button',
207 'blockid' => 'mj3f-z9ggz4',
208 'label' => 'Cake Size',
209 'desc' => '',
210 'multiple' => false,
211 'hide' => false,
212 'required' => false,
213 'vertical' => false,
214 '_options' => array(
215 array(
216 'value' => '1 pound',
217 'type' => 'fixed',
218 'regular' => '26',
219 'sale' => '',
220 ),
221 array(
222 'value' => '3 pound',
223 'type' => 'fixed',
224 'regular' => '78',
225 'sale' => '70',
226 ),
227 array(
228 'value' => '5 pound',
229 'type' => 'fixed',
230 'regular' => '130',
231 'sale' => '',
232 ),
233 ),
234 'class' => '',
235 'id' => '',
236 'defval' => array( 0 ),
237 ),
238 array(
239 'type' => 'radio',
240 'blockid' => 'mc2a-nctpsf',
241 'label' => 'Choose Flavor',
242 'desc' => '',
243 'columns' => '1',
244 'enableCount' => false,
245 'hide' => false,
246 'required' => false,
247 'min' => 1,
248 'max' => 100,
249 'pricePosition' => 'with_option',
250 '_options' => array(
251 array(
252 'value' => 'Strawberry',
253 'type' => 'no_cost',
254 'regular' => '',
255 'sale' => '',
256 'def' => false,
257 ),
258 array(
259 'value' => 'Avocado',
260 'type' => 'no_cost',
261 'regular' => '6',
262 'sale' => '',
263 'def' => false,
264 ),
265 array(
266 'value' => 'Blueberry',
267 'type' => 'fixed',
268 'regular' => '12',
269 'sale' => '',
270 ),
271 array(
272 'value' => 'Chocolate',
273 'type' => 'fixed',
274 'regular' => '10',
275 'sale' => '8',
276 'def' => false,
277 ),
278 ),
279 'en_logic' => false,
280 'fieldConditions' => array(),
281 ),
282 array(
283 'type' => 'button',
284 'blockid' => 'm60j-i43lv3',
285 'label' => 'Cake Tiers',
286 'desc' => '',
287 'multiple' => false,
288 'hide' => false,
289 'required' => false,
290 'vertical' => false,
291 '_options' => array(
292 array(
293 'value' => 'Single',
294 'type' => 'no_cost',
295 'regular' => '8',
296 'sale' => '',
297 ),
298 array(
299 'value' => 'Two - Tier',
300 'type' => 'fixed',
301 'regular' => '6',
302 'sale' => '',
303 ),
304 array(
305 'value' => 'Three - Tier',
306 'type' => 'fixed',
307 'regular' => '8',
308 'sale' => '',
309 ),
310 ),
311 'class' => '',
312 'id' => '',
313 'defval' => array( 0 ),
314 ),
315 array(
316 'type' => 'textfield',
317 'blockid' => 'mbg8-joml77',
318 'label' => 'Message on Cake',
319 'placeholder' => 'Happy Birthday',
320 'pricePosition' => 'with_title',
321 '_options' => array(
322 array(
323 'type' => 'no_cost',
324 'regular' => '2',
325 'sale' => '',
326 ),
327 ),
328 'class' => '',
329 'id' => '',
330 'hide' => false,
331 'required' => false,
332 ),
333 ),
334 ),
335 );
336
337 foreach ( $dummy_content as $addon ) {
338 $attr = array(
339 'post_title' => $addon['title'],
340 'post_status' => 'draft',
341 'post_content' => $addon['title'],
342 'post_type' => 'prad_option',
343 );
344 $id = wp_insert_post( $attr );
345 if ( $id ) {
346 update_post_meta( $id, 'prad_addons_blocks', $addon['content'] );
347 }
348 }
349
350 update_option( 'prad_addons_default_option_created', true );
351 }
352
353 /**
354 * Creates the database table used to store plugin statistics.
355 *
356 * This method is responsible for initializing the stats table structure
357 * in the WordPress database if it does not already exist.
358 *
359 * @global wpdb $wpdb WordPress database access abstraction object.
360 *
361 * @return void
362 */
363 public function create_stats_table() {
364 global $wpdb;
365
366 $sql = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}prad_stats_table` (
367 `id` INT unsigned NOT NULL AUTO_INCREMENT,
368 `option_id` bigint(20) unsigned NOT NULL,
369 `impression_count` INT unsigned NOT NULL default '0',
370 `click_count` INT unsigned NOT NULL default '0',
371 `add_to_cart_count` INT unsigned NOT NULL default '0',
372 `order_count` INT unsigned NOT NULL default '0',
373 `sales` FLOAT NOT NULL default '0',
374 PRIMARY KEY (id),
375 KEY option_id_index (option_id)
376 ) {$wpdb->get_charset_collate()};";
377
378 dbDelta( $sql );
379 }
380
381 /**
382 * Creates the database table used to store statistical graph data.
383 *
384 * This method initializes the stats graph table in the WordPress database
385 * if it does not already exist. The table is typically used to record and
386 * display time-based statistical data for the plugin.
387 *
388 * @global wpdb $wpdb WordPress database access abstraction object.
389 *
390 * @return void
391 */
392 public function create_stats_graph_table() {
393 global $wpdb;
394
395 $sql = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}prad_stats_graph` (
396 `id` INT unsigned NOT NULL AUTO_INCREMENT,
397 `date` date NOT NULL,
398 `impression_count` INT unsigned NOT NULL default '0',
399 `click_count` INT unsigned NOT NULL default '0',
400 `add_to_cart_count` INT unsigned NOT NULL default '0',
401 `order_count` INT unsigned NOT NULL default '0',
402 `sales` FLOAT NOT NULL default '0',
403 PRIMARY KEY (id),
404 KEY option_date (date)
405 ) {$wpdb->get_charset_collate()};";
406
407 dbDelta( $sql );
408 }
409
410 /**
411 * Updates the stats table for a given option and stat type.
412 *
413 * @param int $option_id The ID of the related option or record.
414 * @param string $stat_type The type of statistic to update (e.g., 'views', 'clicks').
415 * @param int|float $count The count value to update or increment.
416 *
417 * @return void
418 */
419 public function update_stats_table( $option_id, $stat_type, $count ) {
420 global $wpdb;
421
422 $table_name = "{$wpdb->prefix}prad_stats_table";
423 if ( $wpdb->get_var( // phpcs:ignore
424 $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name )
425 ) !== $table_name ) {
426 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
427
428 $this->create_stats_table();
429 $this->create_stats_graph_table();
430 }
431
432 $allowed_columns = array(
433 'impression_count',
434 'click_count',
435 'add_to_cart_count',
436 'order_count',
437 'sales',
438 );
439
440 if ( ! in_array( $stat_type, $allowed_columns, true ) ) {
441 return;
442 }
443
444 $date = current_time( 'Y-m-d' );
445 $stat_type = esc_sql( $stat_type );
446
447 $this->update_stats_graph( $date, $stat_type, $count );
448
449 $existing_record = $wpdb->get_row( // phpcs:ignore
450 $wpdb->prepare(
451 "SELECT id, `$stat_type` FROM `{$wpdb->prefix}prad_stats_table` WHERE option_id = %d", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
452 $option_id
453 ),
454 ARRAY_A
455 );
456
457 if ( $existing_record ) {
458 if ( 'sales' === $stat_type ) {
459 $new_count = isset( $existing_record[ $stat_type ] ) ? ( floatval( $existing_record[ $stat_type ] ) + floatval( $count ? $count : 0 ) ) : floatval( $count ? $count : 0 );
460 } else {
461 $new_count = isset( $existing_record[ $stat_type ] ) ? $existing_record[ $stat_type ] + 1 : 1;
462 }
463
464 $wpdb->update( //phpcs:ignore
465 "{$wpdb->prefix}prad_stats_table",
466 array( $stat_type => $new_count ),
467 array( 'id' => $existing_record['id'] ),
468 array( '%f' ),
469 array( '%d' )
470 );
471 } else {
472 $new_count = 'sales' === $stat_type ? 0 : 1;
473
474 $wpdb->insert( //phpcs:ignore
475 "{$wpdb->prefix}prad_stats_table",
476 array(
477 'option_id' => $option_id,
478 $stat_type => $new_count,
479 ),
480 array( '%d', '%s' )
481 );
482 }
483 }
484
485 /**
486 * Updates the stats graph with a new count for the given date and stat type.
487 *
488 * @param string $datekey The date key (e.g., '2025-08-17') used to group statistics.
489 * @param string $stat_type The type of statistic to update (e.g., 'views', 'clicks').
490 * @param int|float $count The count value to update or increment.
491 *
492 * @return void
493 */
494 public function update_stats_graph( $datekey, $stat_type, $count ) {
495 global $wpdb;
496
497 $existing_record = $wpdb->get_row( // phpcs:ignore
498 $wpdb->prepare(
499 "SELECT id, `$stat_type` FROM `{$wpdb->prefix}prad_stats_graph` WHERE date = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
500 $datekey
501 ),
502 ARRAY_A
503 );
504
505 if ( $existing_record ) {
506 if ( 'sales' === $stat_type ) {
507 $new_count = isset( $existing_record[ $stat_type ] ) ? ( floatval( $existing_record[ $stat_type ] ) + floatval( $count ? $count : 0 ) ) : floatval( $count ? $count : 0 );
508 } else {
509 $new_count = isset( $existing_record[ $stat_type ] ) ? $existing_record[ $stat_type ] + 1 : 1;
510 }
511
512 $wpdb->update( // phpcs:ignore
513 "{$wpdb->prefix}prad_stats_graph",
514 array( $stat_type => $new_count ),
515 array( 'id' => $existing_record['id'] ),
516 array( '%f' ),
517 array( '%d' )
518 );
519 } else {
520 $new_count = 'sales' === $stat_type ? 0 : 1;
521
522 $wpdb->insert( // phpcs:ignore
523 "{$wpdb->prefix}prad_stats_graph",
524 array(
525 'date' => $datekey,
526 $stat_type => $new_count,
527 ),
528 array( '%s', '%s' )
529 );
530 }
531 }
532 }
533