PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 3.1.0
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v3.1.0
5.12.0 5.13.0 5.13.1 5.11.0 5.10.0 5.9.0 5.8.0 5.8.1 5.7.0 5.6.2 5.6.3 5.6.1 5.6.0 5.5.0 5.4.0 5.3.2 5.3.1 5.1.6 5.1.5 trunk 2.1.5 2.11 2.12 2.13 2.15 All 47 releases
double-opt-in / core / Category.class.php

Category.class.php in Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification 3.1.0, at core/Category.class.php

544 lines 15.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace forge12\contactform7\CF7DoubleOptIn {
4
5 use Forge12\Shared\Logger;
6 use Forge12\Shared\LoggerInterface;
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * Class Category
14 * Handle the Categories
15 *
16 * @package forge12\contactform7\CF7DoubleOptIn
17 */
18 class Category {
19 /**
20 * Stores the DB ID for the entry
21 *
22 * @var int
23 */
24 private $id = 0;
25
26 /**
27 * The name of the category
28 *
29 * @var string
30 */
31 private $name = '';
32 /**
33 * Stores the timestamp the opt-in mail has been sent to the user.
34 *
35 * @var string
36 */
37 private $createtime = "";
38 /**
39 * Stores the timestamp the opt-in has been confirmed by the user.
40 */
41 private $updatetime = "";
42 private LoggerInterface $logger;
43
44 /**
45 * The constructor
46 */
47 public function __construct( LoggerInterface $logger, array $properties = array() ) {
48 $this->logger = $logger;
49 $this->get_logger()->info( 'Constructor started.', [ 'plugin' => 'double-opt-in' ] );
50
51 foreach ( $properties as $name => $value ) {
52 if ( isset( $this->{$name} ) ) {
53 $this->{$name} = $value;
54 $this->get_logger()->debug( 'Property ' . $name . ' set.', [
55 'plugin' => 'double-opt-in',
56 'property' => $name,
57 'value' => $value,
58 ] );
59 } else {
60 $this->get_logger()->warning( 'Attempted to set a non-existent property.', [
61 'plugin' => 'double-opt-in',
62 'property' => $name,
63 ] );
64 }
65 }
66
67 $this->get_logger()->info( 'Constructor finished successfully.', [ 'plugin' => 'double-opt-in' ] );
68 }
69
70 public function get_logger() {
71 return $this->logger;
72 }
73
74 /**
75 * Return the ID of the Optin
76 *
77 * @return int
78 */
79 public function get_id() {
80 return $this->id;
81 }
82
83 /**
84 * Return the name of the category
85 *
86 * @return string
87 */
88 public function get_name() {
89 return $this->name;
90 }
91
92 /**
93 * Set the name of the category
94 *
95 * @param string $name
96 *
97 * @return void
98 */
99 public function set_name( $name ) {
100 $this->name = $name;
101 }
102
103 /**
104 * @param string $timestamp
105 */
106 public function set_createtime( $timestamp ) {
107 $this->createtime = $timestamp;
108 }
109
110 /**
111 * Return a timestamp
112 *
113 * @param string $view Select how to return the content. raw is the stored db value. use formatted to return a
114 * formatted string.
115 *
116 * @return string
117 */
118 public function get_createtime( $view = "raw" ) {
119 $this->get_logger()->info( 'Getting creation time.', [
120 'plugin' => 'double-opt-in',
121 'view' => $view
122 ] );
123
124 if ( empty( $this->createtime ) ) {
125 $this->get_logger()->warning( 'Creation time is empty. Setting to current time.', [
126 'plugin' => 'double-opt-in'
127 ] );
128 $this->set_createtime( time() );
129 }
130
131 if ( $view != "raw" ) {
132 $this->get_logger()->debug( 'Processing creation time for formatted view.', [
133 'plugin' => 'double-opt-in',
134 'time_value' => $this->createtime
135 ] );
136
137 if ( ! is_numeric( $this->createtime ) ) {
138 $date = date( 'd.m.Y', strtotime( $this->createtime ) );
139 $time = date( 'H:i:s', strtotime( $this->createtime ) );
140 $this->get_logger()->debug( 'Creation time is not numeric. Converting from string.', [
141 'plugin' => 'double-opt-in'
142 ] );
143 } else {
144 $date = date( 'd.m.Y', $this->createtime );
145 $time = date( 'H:i:s', $this->createtime );
146 $this->get_logger()->debug( 'Creation time is numeric. Converting from timestamp.', [
147 'plugin' => 'double-opt-in'
148 ] );
149 }
150
151 $formatted_time = $date . ' ' . __( '/', 'double-opt-in' ) . ' ' . $time;
152 $this->get_logger()->info( 'Returning formatted creation time.', [
153 'plugin' => 'double-opt-in',
154 'formatted_value' => $formatted_time
155 ] );
156 return $formatted_time;
157 } else {
158 $this->get_logger()->info( 'Returning raw creation time.', [
159 'plugin' => 'double-opt-in',
160 'raw_value' => $this->createtime
161 ] );
162 return $this->createtime;
163 }
164 }
165
166 /**
167 * @param string $timestamp
168 */
169 public function set_updatetime( $timestamp ) {
170 $this->updatetime = $timestamp;
171 }
172
173 /**
174 * Return a timestamp
175 *
176 * @param string $view Select how to return the content. raw is the stored db value. use formatted to return a
177 * formatted string.
178 *
179 * @return string
180 */
181 public function get_updatetime( $view = 'raw' ) {
182 $this->get_logger()->info( 'Retrieving update time.', [
183 'plugin' => 'double-opt-in',
184 'view' => $view
185 ] );
186
187 if ( empty( $this->updatetime ) ) {
188 $this->get_logger()->warning( 'Update time is empty. Setting to current time.', [
189 'plugin' => 'double-opt-in'
190 ] );
191 $this->set_updatetime( time() );
192 }
193
194 if ( $view != "raw" ) {
195 $this->get_logger()->debug( 'Processing update time for formatted view.', [
196 'plugin' => 'double-opt-in'
197 ] );
198
199 if ( ! is_numeric( $this->updatetime ) ) {
200 $date = date( 'd.m.Y', strtotime( $this->updatetime ) );
201 $time = date( 'H:i:s', strtotime( $this->updatetime ) );
202 $this->get_logger()->debug( 'Update time is not numeric; converting from string.', [
203 'plugin' => 'double-opt-in'
204 ] );
205 } else {
206 $date = date( 'd.m.Y', $this->updatetime );
207 $time = date( 'H:i:s', $this->updatetime );
208 $this->get_logger()->debug( 'Update time is numeric; converting from timestamp.', [
209 'plugin' => 'double-opt-in'
210 ] );
211 }
212
213 $formatted_time = $date . ' ' . __( '/', 'double-opt-in' ) . ' ' . $time;
214 $this->get_logger()->info( 'Returning formatted update time.', [
215 'plugin' => 'double-opt-in',
216 'formatted_value' => $formatted_time
217 ] );
218 return $formatted_time;
219 } else {
220 $this->get_logger()->info( 'Returning raw update time.', [
221 'plugin' => 'double-opt-in',
222 'raw_value' => $this->updatetime
223 ] );
224 return $this->updatetime;
225 }
226 }
227
228 /**
229 * Return the link to the category
230 *
231 * @return string
232 */
233 public function get_link_ui() {
234 $link = admin_url( 'admin.php?page=f12-cf7-doubleoptin_categories_view&id=' . $this->get_id() );
235
236 $this->get_logger()->info( 'Generating UI link for admin page.', [
237 'plugin' => 'double-opt-in',
238 'link' => $link,
239 'id' => $this->get_id(),
240 ] );
241
242 return $link;
243 }
244
245 /**
246 * Return a list of opt ins stored in the database.
247 *
248 * @param $atts array (
249 * 'perPage' => 10, // Posts per page
250 * 'page' => 0, // Current page
251 * 'order' => DESC, // Order (ASC/DESC)
252 * );
253 *
254 * @param null $numberOfPages - Stores the number of pages found if limited
255 *
256 * @return array<Category>
257 */
258 public static function get_list( $atts = array(), &$numberOfPages = null ) {
259 global $wpdb;
260
261 // Log the start of the get_list function.
262 Logger::getInstance()->info( 'Fetching a list of categories.', [
263 'plugin' => 'double-opt-in',
264 'atts' => $atts,
265 ] );
266
267 $attr = array(
268 'perPage' => 10,
269 'page' => 1,
270 'order' => 'DESC',
271 'orderBy' => 'ID',
272 );
273
274 foreach ( $atts as $key => $value ) {
275 if ( isset( $attr[ $key ] ) ) {
276 $attr[ $key ] = $atts[ $key ];
277 }
278 }
279
280 // Log the final attributes used for the query.
281 Logger::getInstance()->debug( 'Using the following attributes for the query.', [
282 'plugin' => 'double-opt-in',
283 'attributes' => $attr,
284 ] );
285
286 $tableName = $wpdb->prefix . 'f12_cf7_doubleoptin_categories';
287 $pageNum = (int) $attr['page'] - 1;
288
289 if ( $numberOfPages !== null ) {
290 // Log the start of counting items for pagination.
291 Logger::getInstance()->info( 'Counting total items for pagination.', [
292 'plugin' => 'double-opt-in',
293 ] );
294
295 $result = $wpdb->get_row( 'SELECT count(*) AS counter FROM ' . $tableName );
296
297 if ( $result ) {
298 $itemCounter = $result->counter;
299
300 $numberOfPages = 1;
301
302 if ( $attr['perPage'] != - 1 ) {
303 $numberOfPages = ceil( $itemCounter / (int) $attr['perPage'] );
304 }
305 // Log the calculated number of pages.
306 Logger::getInstance()->info( 'Calculated number of pages.', [
307 'plugin' => 'double-opt-in',
308 'total_items' => $itemCounter,
309 'items_per_page' => $attr['perPage'],
310 'total_pages' => $numberOfPages,
311 ] );
312 } else {
313 // Log a potential error if the count query fails.
314 Logger::getInstance()->error( 'Failed to count total items for pagination.', [
315 'plugin' => 'double-opt-in',
316 'query' => $wpdb->last_query,
317 'error' => $wpdb->last_error,
318 ] );
319 }
320 }
321
322 $offset = $pageNum * (int) $attr['perPage'];
323
324 $limit = '';
325
326 if ( $attr['perPage'] != - 1 ) {
327 $limit = ' LIMIT ' . (int) $attr['perPage'] . ' OFFSET ' . $offset;
328 }
329
330 $query = 'SELECT * FROM ' . $tableName . ' ORDER BY ' . $attr['orderBy'] . ' ' . $attr['order'] . $limit;
331 // Log the final query before execution.
332 Logger::getInstance()->debug( 'Executing database query to fetch categories.', [
333 'plugin' => 'double-opt-in',
334 'query' => $query,
335 ] );
336
337 $rows = $wpdb->get_results( $query, ARRAY_A );
338
339 if ( $rows === null ) {
340 // Log a potential error if the main query fails.
341 Logger::getInstance()->error( 'Failed to fetch categories from the database.', [
342 'plugin' => 'double-opt-in',
343 'query' => $wpdb->last_query,
344 'error' => $wpdb->last_error,
345 ] );
346 }
347
348 $list = array();
349 foreach ( $rows as $row ) {
350 $list[] = new Category( Logger::getInstance(), $row );
351 }
352
353 // Log the number of items retrieved.
354 Logger::getInstance()->info( 'Successfully retrieved ' . count($list) . ' categories.', [
355 'plugin' => 'double-opt-in',
356 'count' => count( $list ),
357 ] );
358
359 return $list;
360 }
361
362 /**
363 * Return a Category by the given ID
364 *
365 * @param $id
366 *
367 * @return Category|null
368 */
369 public static function get_by_id( $id ) {
370 global $wpdb;
371
372 // Log the start of the get_by_id function.
373 Logger::getInstance()->info( 'Attempting to retrieve category by ID.', [
374 'plugin' => 'double-opt-in',
375 'id' => $id,
376 ] );
377
378 $table = $wpdb->prefix . 'f12_cf7_doubleoptin_categories';
379
380 $query = $wpdb->prepare( 'SELECT * FROM ' . $table . ' WHERE id=%d', $id );
381
382 // Log the prepared query before execution.
383 Logger::getInstance()->debug( 'Executing database query to get category by ID.', [
384 'plugin' => 'double-opt-in',
385 'query' => $query,
386 ] );
387
388 $rows = $wpdb->get_results( $query, ARRAY_A );
389
390 if ( is_array( $rows ) && ! empty( $rows ) ) {
391 $rows = $rows[0];
392
393 // Log the successful retrieval of the category.
394 Logger::getInstance()->info( 'Category found and retrieved successfully.', [
395 'plugin' => 'double-opt-in',
396 'id' => $id,
397 'category' => $rows,
398 ] );
399
400 return new Category( Logger::getInstance(), $rows );
401 }
402
403 // Log that no category was found with the given ID.
404 Logger::getInstance()->warning( 'No category found with the given ID.', [
405 'plugin' => 'double-opt-in',
406 'id' => $id,
407 ] );
408
409 return null;
410 }
411
412 /**
413 * Delete a Category by the given id. All assigned Opt-Ins will be changed to be uncategorized.
414 *
415 * @param $id
416 *
417 * @return bool|int|\mysqli_result|resource|null
418 */
419 public static function delete_by_id( $id ) {
420 global $wpdb;
421
422 // Log the start of the deletion process.
423 Logger::getInstance()->info( 'Attempting to delete category by ID.', [
424 'plugin' => 'double-opt-in',
425 'id' => $id,
426 ] );
427
428 $table = $wpdb->prefix . 'f12_cf7_doubleoptin_categories';
429
430 // Ensure that the opt in class exists otherwise do nothing.
431 if ( class_exists( 'forge12\contactform7\CF7DoubleOptIn\OptIn' ) ) {
432 // Log the action before updating the category in the OptIn class.
433 Logger::getInstance()->info( 'Updating category for related opt-ins before deletion.', [
434 'plugin' => 'double-opt-in',
435 'old_id' => $id,
436 'new_id' => 0,
437 ] );
438
439 OptIn::bulk_update_category( $id, 0 );
440
441 // Log the deletion from the database.
442 $result = $wpdb->delete( $table, array( 'id' => $id ), array( '%d' ) );
443
444 if ( $result === false ) {
445 // Log an error if the deletion failed.
446 Logger::getInstance()->error( 'Failed to delete category from the database.', [
447 'plugin' => 'double-opt-in',
448 'id' => $id,
449 'error' => $wpdb->last_error,
450 ] );
451 } else {
452 // Log a successful deletion.
453 Logger::getInstance()->notice( 'Category deleted successfully.', [
454 'plugin' => 'double-opt-in',
455 'id' => $id,
456 'rows_deleted' => $result,
457 ] );
458 }
459
460 return $result;
461 }
462
463 // Log that the required class does not exist.
464 Logger::getInstance()->warning( 'Required OptIn class does not exist. Deletion process aborted.', [
465 'plugin' => 'double-opt-in',
466 'id' => $id,
467 ] );
468
469 return false;
470 }
471
472 /**
473 * Update or create the given Object
474 */
475 public function save() {
476 global $wpdb;
477
478 $this->get_logger()->info( 'Attempting to save category data.', [ 'plugin' => 'double-opt-in' ] );
479
480 $table = $wpdb->prefix . 'f12_cf7_doubleoptin_categories';
481
482 if ( ! empty( $this->get_id() ) && $this->get_id() > 0 ) {
483 $this->get_logger()->info( 'Updating existing category.', [
484 'plugin' => 'double-opt-in',
485 'id' => $this->get_id(),
486 ] );
487
488 $result = $wpdb->update( $table, array(
489 'name' => $this->get_name(),
490 'updatetime' => $this->get_updatetime()
491 ), array(
492 'id' => $this->get_id()
493 ) );
494
495 if ( $result === false ) {
496 $this->get_logger()->error( 'Failed to update category.', [
497 'plugin' => 'double-opt-in',
498 'id' => $this->get_id(),
499 'name' => $this->get_name(),
500 'error' => $wpdb->last_error,
501 ] );
502 } else {
503 $this->get_logger()->notice( 'Category updated successfully.', [
504 'plugin' => 'double-opt-in',
505 'id' => $this->get_id(),
506 'rows_affected' => $result,
507 ] );
508 }
509
510 return $result;
511 } else {
512 $this->get_logger()->info( 'Inserting new category.', [ 'plugin' => 'double-opt-in' ] );
513
514 $result = $wpdb->insert( $table, array(
515 'name' => $this->get_name(),
516 'createtime' => $this->get_createtime(),
517 'updatetime' => $this->get_updatetime(),
518 ) );
519
520 if ( $result > 0 ) {
521 $this->id = $wpdb->insert_id;
522 $this->get_logger()->notice( 'New category inserted successfully.', [
523 'plugin' => 'double-opt-in',
524 'id' => $this->id,
525 'name' => $this->get_name(),
526 ] );
527 return $this->id;
528 } else {
529 $this->get_logger()->error( 'Failed to insert new category.', [
530 'plugin' => 'double-opt-in',
531 'name' => $this->get_name(),
532 'error' => $wpdb->last_error,
533 ] );
534 }
535 }
536
537 $this->get_logger()->critical( 'Save operation failed for an unknown reason.', [
538 'plugin' => 'double-opt-in',
539 ] );
540
541 return false;
542 }
543 }
544 }