PluginProbe
Tutor LMS – eLearning and online course solution / 3.7.2
Tutor LMS – eLearning and online course solution v3.7.2
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 All 191 releases
← All changes | helpers/QueryHelper.php +173 -434 trunk3.7.2 View file →
@@ -3,9 +3,9 @@
3 3 * Query helper class contains static helper methods to perform basic
4 4 * operations
5 5 *
6 6 * @package Tutor\Helper
7 - * @since 2.0.7
7 + * @since v2.0.7
8 8 */
9 9
10 10 namespace Tutor\Helpers;
11 11
@@ -31,10 +31,9 @@
31 31 */
32 32 public static function insert( string $table, array $data, array $sanitize_mapping = array() ): int {
33 33 global $wpdb;
34 34
35 - $table = self::prepare_table_name( $table );
36 - $data = \TUTOR\Input::sanitize_array( $data, $sanitize_mapping );
35 + $data = \TUTOR\Input::sanitize_array( $data, $sanitize_mapping );
37 36
38 37 $insert = $wpdb->insert(
39 38 $table,
40 39 $data
@@ -61,11 +60,10 @@
61 60 */
62 61 public static function update( string $table, array $data, array $where ): bool {
63 62 global $wpdb;
64 63
65 - $table = self::prepare_table_name( $table );
66 64 $set_clause = self::prepare_set_clause( $data );
67 - $where_clause = self::prepare_where_clause( $where );
65 + $where_clause = self::build_where_clause( $where );
68 66
69 67 // phpcs:ignore
70 68 $query = $wpdb->prepare( "UPDATE {$table} {$set_clause} WHERE {$where_clause} AND 1 = %d", 1 );
71 69
@@ -92,10 +90,8 @@
92 90 * @since v2.0.7
93 91 */
94 92 public static function delete( string $table, array $where ): bool {
95 93 global $wpdb;
96 -
97 - $table = self::prepare_table_name( $table );
98 94 $delete = $wpdb->delete(
99 95 $table,
100 96 $where
101 97 );
@@ -112,13 +108,10 @@
112 108 *
113 109 * @return int|boolean
114 110 */
115 111 public static function bulk_delete( $table, array $where ): bool {
112 + $where_clause = self::build_where_clause( $where );
116 113 global $wpdb;
117 -
118 - $table = self::prepare_table_name( $table );
119 - $where_clause = self::prepare_where_clause( $where );
120 -
121 114 return $wpdb->query( "DELETE FROM {$table} WHERE {$where_clause}" ); //phpcs:ignore --$where clause sanitized.
122 115 }
123 116
124 117 /**
@@ -137,10 +130,9 @@
137 130 */
138 131 public static function bulk_delete_by_ids( string $table, array $ids ): bool {
139 132 global $wpdb;
140 133
141 - $table = self::prepare_table_name( $table );
142 - $ids = self::prepare_in_clause( $ids );
134 + $ids = self::prepare_in_clause( $ids );
143 135 //phpcs:ignore --ids already sanitized.
144 136 $wpdb->query( "DELETE FROM {$table} WHERE id IN ( $ids )");
145 137
146 138 if ( $wpdb->last_error ) {
@@ -160,10 +152,8 @@
160 152 * @return bool
161 153 */
162 154 public static function table_clean( string $table ): bool {
163 155 global $wpdb;
164 -
165 - $table = self::prepare_table_name( $table );
166 156 $delete = $wpdb->query(
167 157 //phpcs:ignore
168 158 $wpdb->prepare( "DELETE FROM {$table} WHERE 1 = %d", 1 )
169 159 );
@@ -186,16 +176,10 @@
186 176 * @throws \Exception If error occur.
187 177 */
188 178 public static function insert_multiple_rows( $table, $request, $return_ids = false, $do_sanitize = true ) {
189 179 global $wpdb;
190 -
191 - if ( ! tutor_utils()->is_multi_dimensional_array( $request ) ) {
192 - return self::insert( $table, $request );
193 - }
194 -
195 - $table = self::prepare_table_name( $table );
196 180 $column_keys = '';
197 - $column_values = array();
181 + $column_values = '';
198 182 $sql = '';
199 183 $last_key = array_key_last( $request );
200 184 $first_key = array_key_first( $request );
201 185 foreach ( $request as $k => $value ) {
@@ -200,10 +184,8 @@
200 184 $first_key = array_key_first( $request );
201 185 foreach ( $request as $k => $value ) {
202 186 $keys = array_keys( $value );
203 187
204 - $value_placeholder = array();
205 -
206 188 // Prepare column keys & values.
207 189 foreach ( $keys as $v ) {
208 190 $column_keys .= sanitize_key( $v ) . ',';
209 191 $sanitize_value = $value[ $v ];
@@ -209,39 +191,27 @@
209 191 $sanitize_value = $value[ $v ];
210 192 if ( $sanitize_value && $do_sanitize ) {
211 193 $sanitize_value = sanitize_text_field( $sanitize_value );
212 194 }
213 -
214 - $column_values[] = $sanitize_value;
215 -
216 - $value_placeholder[] = '%s';
195 + $column_values .= is_numeric( $sanitize_value ) ? $sanitize_value . ',' : "'$sanitize_value'" . ',';
217 196 }
218 -
219 - $value_placeholder = implode( ',', $value_placeholder );
220 -
221 197 // Trim trailing comma.
222 198 $column_keys = rtrim( $column_keys, ',' );
223 - $column_values = $wpdb->prepare( $value_placeholder, $column_values ); // Escape values.
224 -
199 + $column_values = rtrim( $column_values, ',' );
225 200 if ( $first_key === $k ) {
226 - $sql .= "INSERT INTO
227 - {$table}
228 - ($column_keys) VALUES ($column_values)
229 - ";
230 -
201 + $sql .= "INSERT INTO {$table} ($column_keys) VALUES ($column_values)";
231 202 if ( count( $request ) > 1 ) {
232 203 $sql .= ',';
233 204 }
234 205 } elseif ( $last_key == $k ) {
235 - $sql .= "( $column_values )";
206 + $sql .= "($column_values)";
236 207 } else {
237 - $sql .= "( $column_values ),";
238 -
208 + $sql .= "($column_values),";
239 209 }
240 210
241 211 // Reset keys & values to avoid duplication.
242 212 $column_keys = '';
243 - $column_values = array();
213 + $column_values = '';
244 214 }
245 215
246 216 $wpdb->query( $sql );//phpcs:ignore
247 217
@@ -246,9 +216,9 @@
246 216 $wpdb->query( $sql );//phpcs:ignore
247 217
248 218 // If error occurred then throw new exception.
249 219 if ( $wpdb->last_error ) {
250 - throw new \Exception( esc_html( $wpdb->last_error ) );
220 + throw new \Exception( $wpdb->last_error );
251 221 }
252 222
253 223 if ( $return_ids ) {
254 224 $query_ids = $wpdb->get_results(
@@ -269,9 +239,8 @@
269 239 * If the operator is IN then make the clause like `WHERE column_name IN (value1, value2, ...)`
270 240 * Otherwise the clause would be `WHERE column_name = 'value'`
271 241 *
272 242 * @since 3.0.0
273 - * @since 3.9.7 added prepared statement for value.
274 243 *
275 244 * @param array $where The where clause array. e.g. array( 'id', 'IN', array(1, 2, 3) ) or array( 'id', '=', 1 ).
276 245 *
277 246 * @return string
@@ -279,18 +248,10 @@
279 248 public static function make_clause( array $where ) {
280 249 list ( $field, $operator, $value ) = $where;
281 250
282 251 $upper_operator = strtoupper( $operator );
283 -
284 252 if ( in_array( $upper_operator, array( 'IN', 'NOT IN' ), true ) ) {
285 253 $value = '(' . self::prepare_in_clause( $value ) . ')';
286 - } elseif ( in_array( $upper_operator, array( 'BETWEEN', 'NOT BETWEEN' ), true ) ) {
287 - $value = array_map( fn( $val ) => self::prepare_value( $val ), $value );
288 - $value = implode( ' AND ', $value );
289 - } elseif ( strtoupper( $value ) === 'NULL' ) {
290 - $value = 'NULL';
291 - } else {
292 - $value = self::prepare_value( $value );
293 254 }
294 255
295 256 return "{$field} {$upper_operator} {$value}";
296 257 }
@@ -331,9 +292,9 @@
331 292 );
332 293 }
333 294
334 295 /**
335 - * Prepare where clause string
296 + * Build where clause string
336 297 *
337 298 * @since 2.0.9
338 299 * @since 3.0.0 Null value support added, if need to check with null: [name => 'null']
339 300 * @since 3.5.0 All common SQL comparison operators support added.
@@ -354,9 +315,9 @@
354 315 * @param array $where assoc array with field and value.
355 316 *
356 317 * @return string
357 318 */
358 - public static function prepare_where_clause( array $where ) {
319 + public static function build_where_clause( array $where ) {
359 320 $arr = array();
360 321 foreach ( $where as $field => $value ) {
361 322 $operator = null;
362 323 if ( is_array( $value ) && isset( $value[0] ) && is_string( $value[0] ) && self::is_support_operator( $value[0] ) ) {
@@ -372,15 +333,17 @@
372 333
373 334 case 'BETWEEN':
374 335 case 'NOT BETWEEN':
375 336 if ( is_array( $val ) && count( $val ) === 2 ) {
376 - $clause = array( $field, $operator, $val );
337 + $val1 = is_numeric( $val[0] ) ? $val[0] : "'" . $val[0] . "'";
338 + $val2 = is_numeric( $val[1] ) ? $val[1] : "'" . $val[1] . "'";
339 + $clause = array( $field, $operator, "{$val1} AND {$val2}" );
377 340 }
378 341 break;
379 342
380 343 case 'IS':
381 344 case 'IS NOT':
382 - $val = strtoupper( $val ) === 'NULL' ? 'NULL' : $val;
345 + $val = strtoupper( $val ) === 'NULL' ? 'NULL' : "'" . $val . "'";
383 346 $clause = array( $field, $operator, $val );
384 347 break;
385 348 case 'RAW':
386 349 $final_query = '';
@@ -389,17 +352,21 @@
389 352 }
390 353 $clause = $final_query;
391 354 break;
392 355 default: // =, !=, <, >, <=, >=, LIKE, NOT LIKE, <>
356 + $val = is_numeric( $val ) ? $val : "'" . $val . "'";
393 357 $clause = array( $field, $operator, $val );
394 358 break;
395 359 }
396 360 } elseif ( is_array( $value ) ) {
397 361 $clause = array( $field, 'IN', $value );
398 - } elseif ( 'null' === strtolower( $value ) ) {
399 - $clause = array( $field, 'IS', 'NULL' );
400 362 } else {
401 - $clause = array( $field, '=', $value );
363 + if ( 'null' === strtolower( $value ) ) {
364 + $clause = array( $field, 'IS', 'NULL' );
365 + } else {
366 + $value = is_numeric( $value ) ? $value : "'" . $value . "'";
367 + $clause = array( $field, '=', $value );
368 + }
402 369 }
403 370
404 371 $arr[] = ( 'RAW' === $operator ) ? $clause : self::make_clause( $clause );
405 372 }
@@ -438,9 +405,9 @@
438 405 return $final_query;
439 406 }
440 407
441 408 /**
442 - * Prepare like clause string with or
409 + * Build like clause string with or
443 410 *
444 411 * @since 1.0.0
445 412 *
446 413 * @param array $where assoc array with field and value.
@@ -447,9 +414,9 @@
447 414 * @param string $relation default is OR.
448 415 *
449 416 * @return string
450 417 */
451 - public static function prepare_like_clause( array $where, $relation = 'OR' ) {
418 + public static function build_like_clause( array $where, $relation = 'OR' ) {
452 419 global $wpdb;
453 420
454 421 $like_conditions = array();
455 422
@@ -493,17 +460,17 @@
493 460 if ( count( $where ) === 0 || ! tutor_utils()->is_assoc( $where ) ) {
494 461 return false;
495 462 }
496 463
497 - $where = self::prepare_where_clause( self::sanitize_assoc_array( $where ) );
464 + $where = self::build_where_clause( self::sanitize_assoc_array( $where ) );
498 465
499 466 global $wpdb;
500 467 $ids = $wpdb->get_col( "SELECT comment_id FROM {$wpdb->comments} WHERE {$where}" );//phpcs:ignore
501 468
502 469 if ( is_array( $ids ) && count( $ids ) ) {
503 - $in_clause = self::prepare_in_clause( $ids );
470 + $ids_str = "'" . implode( "','", $ids ) . "'";
504 471 // delete comment metas.
505 - $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->commentmeta} WHERE comment_id IN({$in_clause}) " ) );//phpcs:ignore
472 + $wpdb->query( "DELETE FROM {$wpdb->commentmeta} WHERE comment_id IN({$ids_str}) " );//phpcs:ignore
506 473 // delete comment.
507 474 $wpdb->query( "DELETE FROM {$wpdb->comments} WHERE {$where}" );//phpcs:ignore
508 475
509 476 return true;
@@ -525,17 +492,17 @@
525 492 if ( count( $where ) === 0 || ! tutor_utils()->is_assoc( $where ) ) {
526 493 return false;
527 494 }
528 495
529 - $where = self::prepare_where_clause( self::sanitize_assoc_array( $where ) );
496 + $where = self::build_where_clause( self::sanitize_assoc_array( $where ) );
530 497
531 498 global $wpdb;
532 499 $ids = $wpdb->get_col( "SELECT id FROM {$wpdb->posts} WHERE {$where}" );//phpcs:ignore
533 500
534 501 if ( is_array( $ids ) && count( $ids ) ) {
535 - $in_clause = self::prepare_in_clause( $ids );
502 + $ids_str = "'" . implode( "','", $ids ) . "'";
536 503 // delete post metas.
537 - $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN({$in_clause}) " ) );//phpcs:ignore
504 + $wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN({$ids_str}) " );//phpcs:ignore
538 505 // delete post.
539 506 $wpdb->query( "DELETE FROM {$wpdb->posts} WHERE {$where}" );//phpcs:ignore
540 507
541 508 return true;
@@ -544,254 +511,8 @@
544 511 return false;
545 512 }
546 513
547 514 /**
548 - * Prepare SELECT clause.
549 - *
550 - * @since 3.8.0
551 - *
552 - * @param mixed $columns Column name or list of columns.
553 - *
554 - * @return string
555 - */
556 - protected static function prepare_select_clause( $columns = '' ) {
557 - if ( empty( $columns ) ) {
558 - return '*';
559 - }
560 -
561 - if ( is_array( $columns ) ) {
562 - return implode( ',', $columns );
563 - }
564 -
565 - return $columns;
566 - }
567 -
568 - /**
569 - * Prepare JOIN clause.
570 - *
571 - * @since 3.8.0
572 - *
573 - * @param array $joins Array of joins, each item:
574 - * - type: join type (LEFT, INNER, RIGHT etc).
575 - * - table: table name.
576 - * - on: join condition.
577 - *
578 - * @return string
579 - */
580 - protected static function prepare_join_clause( $joins = array() ) {
581 - if ( empty( $joins ) || ! is_array( $joins ) ) {
582 - return '';
583 - }
584 -
585 - $clause = '';
586 - foreach ( $joins as $join ) {
587 - $type = strtoupper( $join['type'] ?? 'LEFT' );
588 - $table = self::prepare_table_name( $join['table'] );
589 - $on = $join['on'];
590 - if ( $table && $on ) {
591 - $clause .= " {$type} JOIN {$table} ON {$on} ";
592 - }
593 - }
594 -
595 - return $clause;
596 - }
597 -
598 - /**
599 - * Prepare WHERE + SEARCH clause together.
600 - *
601 - * @since 3.8.0
602 - *
603 - * @param array $where Array of key => value pairs.
604 - * @param array $search Array of key => search string pairs.
605 - * @param string $search_operator Operator for search conditions (AND/OR).
606 - *
607 - * @return string
608 - */
609 - protected static function prepare_where_search_clause( $where = array(), $search = array(), $search_operator = 'OR' ) {
610 - $clauses = array();
611 -
612 - // Handle WHERE conditions.
613 - if ( ! empty( $where ) && is_array( $where ) ) {
614 - $clauses[] = self::prepare_where_clause( $where );
615 - }
616 -
617 - // Handle SEARCH conditions.
618 - if ( ! empty( $search ) && is_array( $search ) ) {
619 - $clauses[] = self::prepare_like_clause( $search, $search_operator );
620 - }
621 -
622 - if ( empty( $clauses ) ) {
623 - return '';
624 - }
625 -
626 - return 'WHERE ' . implode( ' AND ', $clauses );
627 - }
628 -
629 - /**
630 - * Prepare order by clause.
631 - *
632 - * @since 3.8.0
633 - *
634 - * @param string $orderby order by column.
635 - * @param string $order order ASC|DESC.
636 - *
637 - * @return string
638 - */
639 - protected static function prepare_order_clause( $orderby = '', $order = 'DESC' ) {
640 - if ( empty( $orderby ) ) {
641 - return '';
642 - }
643 -
644 - // Allowed: foo, foo_bar, _foo, foo.bar etc.
645 - if ( ! preg_match( '/^[A-Za-z_][A-Za-z0-9._]*$/', $orderby ) ) {
646 - return '';
647 - }
648 -
649 - $order = strtoupper( $order ) === 'ASC' ? 'ASC' : 'DESC';
650 - return "ORDER BY {$orderby} {$order}";
651 - }
652 -
653 - /**
654 - * Prepare LIMIT clause.
655 - *
656 - * @since 3.8.0
657 - *
658 - * @param int $limit limit.
659 - * @param int $offset offset.
660 - *
661 - * @return string
662 - */
663 - protected static function prepare_limit_clause( $limit = 0, $offset = 0 ) {
664 - if ( $limit < 1 || $offset < 0 ) {
665 - return '';
666 - }
667 -
668 - return sprintf( 'LIMIT %d OFFSET %d', $limit, $offset );
669 - }
670 -
671 - /**
672 - * Run a database query with flexible arguments.
673 - *
674 - * Supports SELECT, JOIN, WHERE, SEARCH, GROUP BY, HAVING, ORDER BY,
675 - * LIMIT (pagination), and can return count, single row or full result set.
676 - *
677 - * @since 3.8.0
678 - *
679 - * @param string $table table name.
680 - * @param array $args {
681 - * Query arguments.
682 - *
683 - * @type string|array $select Columns to select, defaults to "*".
684 - * @type string $alias Table alias.
685 - * @type array $where WHERE conditions [ 'col' => 'val', ... ].
686 - * @type array $search LIKE conditions [ 'col' => 'keyword', ... ].
687 - * @type array $joins JOIN clauses [ [ 'type' => 'LEFT', 'table' => '...', 'on' => '...' ], ... ].
688 - * @type string $groupby GROUP BY clause.
689 - * @type string $having HAVING clause.
690 - * @type string $orderby Column to order by.
691 - * @type string $order ASC|DESC, default DESC.
692 - * @type int $limit Limit.
693 - * @type int $offset Offset.
694 - * @type int $per_page Results per page for pagination.
695 - * @type int $page Current page number for pagination.
696 - * @type bool $count If true, return only total count.
697 - * @type bool $single If true, return only single row.
698 - * @type string $output OBJECT|ARRAY_A default is OBJECT.
699 - * }
700 - *
701 - * @return mixed Result set, count or single row.
702 - */
703 - public static function query( $table, $args = array() ) {
704 - // Flags.
705 - $count = isset( $args['count'] ) && $args['count'];
706 - $single = isset( $args['single'] ) && $args['single'];
707 - $pagination = isset( $args['per_page'], $args['page'] );
708 - $output = $args['output'] ?? 'OBJECT';
709 -
710 - // Primary table.
711 - $table = self::prepare_table_name( $table );
712 - $alias = $args['alias'] ?? 'main';
713 - $table_with_alias = "{$table} AS {$alias}";
714 -
715 - // Build clauses.
716 - $select_clause = self::prepare_select_clause( $args['select'] ?? '' );
717 - $join_clause = self::prepare_join_clause( $args['joins'] ?? array() );
718 - $where_clause = self::prepare_where_search_clause( $args['where'] ?? array(), $args['search'] ?? array() );
719 - $groupby_clause = empty( $args['groupby'] ) ? '' : 'GROUP BY ' . $args['groupby'];
720 - $having_clause = empty( $args['having'] ) ? '' : 'HAVING ' . $args['having'];
721 - $order_by_clause = self::prepare_order_clause( $args['orderby'] ?? '', $args['order'] ?? 'DESC' );
722 -
723 - global $wpdb;
724 -
725 - // Count only.
726 - if ( $count ) {
727 - $sql_query = "SELECT COUNT(*)
728 - FROM {$table_with_alias}
729 - {$join_clause}
730 - {$where_clause}
731 - {$groupby_clause}
732 - {$having_clause}";
733 -
734 - return (int) $wpdb->get_var( $sql_query ); //phpcs:ignore
735 - }
736 -
737 - // Single record.
738 - if ( $single ) {
739 - $sql_query = "SELECT {$select_clause}
740 - FROM {$table_with_alias}
741 - {$join_clause}
742 - {$where_clause}
743 - {$groupby_clause}
744 - {$having_clause}
745 - {$order_by_clause}
746 - LIMIT 1";
747 -
748 - return $wpdb->get_row( $sql_query, $output ); //phpcs:ignore
749 - }
750 -
751 - $calc_found_rows = $pagination ? 'SQL_CALC_FOUND_ROWS' : '';
752 - $limit = isset( $args['limit'] ) ? (int) $args['limit'] : 0;
753 - $offset = isset( $args['offset'] ) ? (int) $args['offset'] : 0;
754 -
755 - if ( $pagination ) {
756 - $limit = (int) $args['per_page'];
757 - $offset = (int) ( $args['page'] - 1 ) * $limit;
758 - }
759 -
760 - $limit_clause = self::prepare_limit_clause( $limit, $offset );
761 -
762 - $sql_query = "SELECT {$calc_found_rows} {$select_clause}
763 - FROM {$table_with_alias}
764 - {$join_clause}
765 - {$where_clause}
766 - {$groupby_clause}
767 - {$having_clause}
768 - {$order_by_clause}
769 - {$limit_clause}";
770 -
771 - $rows = $wpdb->get_results( $sql_query, $output ); //phpcs:ignore
772 -
773 - if ( $pagination ) {
774 - $has_records = is_array( $rows ) && count( $rows );
775 - $page = (int) $args['page'];
776 - $per_page = (int) $args['per_page'];
777 - $total_record = (int) $has_records ? $wpdb->get_var( 'SELECT FOUND_ROWS()' ) : 0;
778 - $total_page = (int) ceil( $total_record / $per_page );
779 -
780 - return array(
781 - 'total_record' => (int) $total_record,
782 - 'per_page' => $per_page,
783 - 'current_page' => $page,
784 - 'total_page' => $total_page,
785 - 'data' => $rows,
786 - );
787 -
788 - }
789 -
790 - return $rows;
791 - }
792 -
793 - /**
794 515 * Get a single row from any table with where clause
795 516 *
796 517 * @param string $table table name with prefix.
797 518 *
@@ -804,10 +525,9 @@
804 525 */
805 526 public static function get_row( string $table, array $where, string $order_by, string $order = 'DESC', string $output = 'OBJECT' ) {
806 527 global $wpdb;
807 528
808 - $table = self::prepare_table_name( $table );
809 - $where_clause = self::prepare_where_clause( $where );
529 + $where_clause = self::build_where_clause( $where );
810 530
811 531 //phpcs:disable
812 532 $query = $wpdb->prepare(
813 533 "SELECT *
@@ -844,14 +564,9 @@
844 564 */
845 565 public static function get_all( string $table, array $where, string $order_by, $limit = 1000, string $order = 'DESC', string $output = 'OBJECT' ) {
846 566 global $wpdb;
847 567
848 - $table = self::prepare_table_name( $table );
849 - $where_clause = self::prepare_where_clause( $where );
850 - if ( ! empty( $where_clause ) ) {
851 - $where_clause = "WHERE {$where_clause}";
852 - }
853 -
568 + $where_clause = self::build_where_clause( $where );
854 569 $limit = (int) sanitize_text_field( $limit );
855 570 $limit_clause = ( -1 === $limit ) ? '' : 'LIMIT ' . $limit;
856 571
857 572 //phpcs:disable
@@ -856,9 +571,9 @@
856 571
857 572 //phpcs:disable
858 573 $query = "SELECT *
859 574 FROM {$table}
860 - {$where_clause}
575 + WHERE {$where_clause}
861 576 ORDER BY {$order_by} {$order}
862 577 {$limit_clause}";
863 578
864 579 return $wpdb->get_results(
@@ -883,10 +598,8 @@
883 598 * @return bool true on success, false on failure
884 599 */
885 600 public static function update_where_in( string $table, array $data, string $where_in, string $where_col = 'ID' ) {
886 601 global $wpdb;
887 -
888 - $table = self::prepare_table_name( $table );
889 602 if ( empty( $where_in ) || empty( $where_col ) ) {
890 603 return false;
891 604 }
892 605 $set_clause = self::prepare_set_clause( $data );
@@ -937,42 +650,33 @@
937 650 return rtrim( $set, ',' );
938 651 }
939 652
940 653 /**
941 - * Prepare value before using in query.
942 - *
943 - * @since 3.9.7
944 - *
945 - * @param string|int|float $value the value to prepare.
946 - *
947 - * @return mixed
948 - */
949 - public static function prepare_value( $value ) {
950 - global $wpdb;
951 - $escaped_value = null;
952 - if ( is_int( $value ) ) {
953 - $escaped_value = $wpdb->prepare( '%d', $value );
954 - } elseif ( is_float( $value ) ) {
955 - list( $whole, $decimal ) = explode( '.', $value );
956 - $expression = '%.'. strlen( $decimal ) . 'f';
957 - $escaped_value = $wpdb->prepare( $expression, $value );
958 - } else {
959 - $escaped_value = $wpdb->prepare( '%s', $value );
960 - }
961 - return $escaped_value;
962 - }
963 -
964 - /**
965 654 * Make sanitized SQL IN clause value from an array
966 655 *
967 - * @since 2.1.1
968 - *
969 656 * @param array $arr a sequential array.
970 - *
971 657 * @return string
658 + * @since 2.1.1
972 659 */
973 660 public static function prepare_in_clause( array $arr ) {
974 - $escaped = array_map( fn( $value ) => self::prepare_value( $value ), $arr );
661 + $escaped = array_map(
662 + function( $value ) {
663 + global $wpdb;
664 + $escaped_value = null;
665 + if ( is_int( $value ) ) {
666 + $escaped_value = $wpdb->prepare( '%d', $value );
667 + } else if( is_float( $value ) ) {
668 + list( $whole, $decimal ) = explode( '.', $value );
669 + $expression = '%.'. strlen( $decimal ) . 'f';
670 + $escaped_value = $wpdb->prepare( $expression, $value );
671 + } else {
672 + $escaped_value = $wpdb->prepare( '%s', $value );
673 + }
674 + return $escaped_value;
675 + },
676 + $arr
677 + );
678 +
975 679 return implode( ',', $escaped );
976 680 }
977 681
978 682 /**
@@ -985,11 +689,9 @@
985 689 * @return bool
986 690 */
987 691 public static function table_exists( $table ) {
988 692 global $wpdb;
989 -
990 - $table = self::prepare_table_name( $table );
991 - $sql = "SHOW TABLES LIKE '{$table}'";
693 + $sql = "SHOW TABLES LIKE '{$table}'";
992 694 return $wpdb->get_var( $sql ) === $table;
993 695 }
994 696
995 697 /**
@@ -1003,11 +705,9 @@
1003 705 * @return bool
1004 706 */
1005 707 public static function column_exist( $table, $column ) {
1006 708 global $wpdb;
1007 -
1008 - $table = self::prepare_table_name( $table );
1009 - $sql = "SHOW COLUMNS FROM {$table} LIKE '{$column}'";
709 + $sql = "SHOW COLUMNS FROM {$table} LIKE '{$column}'";
1010 710 return $wpdb->get_var( $sql ) === $column;
1011 711 }
1012 712
1013 713 /**
@@ -1015,9 +715,8 @@
1015 715 *
1016 716 * Argument should be SQL escaped.
1017 717 *
1018 718 * @since 3.0.0
1019 - * @since 3.8.2 param $get_row added.
1020 719 *
1021 720 * @param string $primary_table The primary table name with prefix.
1022 721 * @param array $joining_tables An array of join relations. Each relation should be an array with keys 'type', 'table', 'on'.
1023 722 * @param array $select_columns An array of columns to select.
@@ -1027,9 +726,8 @@
1027 726 * @param int $limit Maximum number of rows to return.
1028 727 * @param int $offset Offset for pagination.
1029 728 * @param string $order DESC or ASC, default is DESC.
1030 729 * @param string $output Expected output type, default is OBJECT.
1031 - * @param bool $get_row Get a single row.
1032 730 *
1033 731 * @throws \Exception If an error occurred during the query execution.
1034 732 *
1035 733 * @return mixed Based on output param, default OBJECT.
@@ -1043,44 +741,74 @@
1043 741 string $order_by = '',
1044 742 $limit = 10,
1045 743 $offset = 0,
1046 744 string $order = 'DESC',
1047 - string $output = 'OBJECT',
1048 - bool $get_row = false
745 + string $output = 'OBJECT'
1049 746 ) {
1050 747 global $wpdb;
1051 748
1052 - $select_clause = implode( ', ', $select_columns );
1053 - $from_clause = self::prepare_table_name( $primary_table );
1054 - $join_clauses = self::prepare_join_clause( $joining_tables );
1055 - $where_clause = self::prepare_where_search_clause( $where, $search );
1056 - $order_by_clause = self::prepare_order_clause( $order_by, $order );
1057 - $limit_clause = self::prepare_limit_clause( $limit, $offset );
749 + $select_clause = implode(', ', $select_columns);
1058 750
1059 - $query = "SELECT SQL_CALC_FOUND_ROWS
751 + $from_clause = $primary_table;
752 +
753 + $join_clauses = '';
754 + foreach ($joining_tables as $relation) {
755 + $join_clauses .= " {$relation['type']} JOIN {$relation['table']} ON {$relation['on']}";
756 + }
757 +
758 + $where_clause = !empty($where) ? 'WHERE ' . self::build_where_clause($where) : '';
759 +
760 + if (!empty($search)) {
761 + $search_clause = self::build_like_clause( $search );
762 + // foreach ($search as $column => $value) {
763 + // $search_clauses[] = $wpdb->prepare("{$column} LIKE %s", '%' . $wpdb->esc_like($value) . '%');
764 + // }
765 + $where_clause .= !empty($where_clause) ? ' AND (' . $search_clause . ')' : 'WHERE ' . $search_clause;
766 + }
767 +
768 + $order_by_clause = !empty($order_by) ? "ORDER BY {$order_by} {$order}" : '';
769 +
770 + // Query to get total count.
771 + $count_query = "
772 + SELECT COUNT(*) as total_count
773 + FROM {$from_clause}
774 + {$join_clauses}
775 + {$where_clause}
776 + ";
777 +
778 + $total_count = $wpdb->get_var($count_query);
779 +
780 + if (empty($limit) && empty($offset)) {
781 + $query = "SELECT
1060 782 {$select_clause}
1061 783 FROM {$from_clause}
1062 784 {$join_clauses}
1063 785 {$where_clause}
786 + {$order_by_clause}";
787 + } else {
788 + $query = $wpdb->prepare(
789 + "SELECT {$select_clause}
790 + FROM {$from_clause}
791 + {$join_clauses}
792 + {$where_clause}
1064 793 {$order_by_clause}
1065 - {$limit_clause}";
794 + LIMIT %d OFFSET %d",
795 + $limit,
796 + $offset
797 + );
798 + }
1066 799
1067 - if ( $get_row ) {
1068 - return $wpdb->get_row( $query, $output );
1069 - }
1070 800
1071 - $results = $wpdb->get_results( $query, $output );
1072 - $has_records = is_array( $results ) && count( $results );
1073 - $total_count = $has_records ? (int) $wpdb->get_var( 'SELECT FOUND_ROWS()' ) : 0;
801 + $results = $wpdb->get_results($query, $output);
1074 802
1075 803 // Throw exception if error occurred.
1076 - if ( $wpdb->last_error ) {
1077 - throw new \Exception( $wpdb->last_error );
804 + if ($wpdb->last_error) {
805 + throw new \Exception($wpdb->last_error);
1078 806 }
1079 807
1080 808 // Prepare response array.
1081 809 $response = array(
1082 - 'total_count' => $total_count,
810 + 'total_count' => (int) $total_count,
1083 811 'results' => $results,
1084 812 );
1085 813
1086 814 return $response;
@@ -1102,11 +830,19 @@
1102 830 */
1103 831 public static function get_count( $table, $where = [], $search = [], $count_column = 'id' ): int {
1104 832 global $wpdb;
1105 833
1106 - $table = self::prepare_table_name( $table );
1107 - $where_clause = self::prepare_where_search_clause( $where, $search, 'AND' );
834 + $where_clause = !empty( $where ) ? 'WHERE ' . self::build_where_clause( $where ) : '';
835 + $search_clause = !empty( $search ) ? self::build_like_clause( $search, 'AND' ) : '';
1108 836
837 + if ( !empty( $search_clause ) ) {
838 + if ( !empty( $where_clause ) ) {
839 + $where_clause .= ' AND (' . $search_clause . ')';
840 + } else {
841 + $where_clause = 'WHERE ' . $search_clause;
842 + }
843 + }
844 +
1109 845 $count = $wpdb->get_var(
1110 846 "SELECT COUNT($count_column)
1111 847 FROM $table
1112 848 {$where_clause}"
@@ -1137,12 +873,26 @@
1137 873 */
1138 874 public static function get_joined_count(string $primary_table, array $joining_tables, array $where = [], array $search = [], string $count_column = '*'): int {
1139 875 global $wpdb;
1140 876
1141 - $from_clause = self::prepare_table_name( $primary_table );
1142 - $join_clauses = self::prepare_join_clause( $joining_tables );
1143 - $where_clause = self::prepare_where_search_clause( $where, $search, 'AND' );
877 + $from_clause = $primary_table;
878 +
879 + $join_clauses = '';
880 + foreach ($joining_tables as $relation) {
881 + $join_clauses .= " {$relation['type']} JOIN {$relation['table']} ON {$relation['on']}";
882 + }
883 +
884 + $where_clause = !empty($where) ? 'WHERE ' . self::build_where_clause($where) : '';
885 + $search_clause = !empty($search) ? self::build_like_clause($search, 'AND') : '';
1144 886
887 + if (!empty($search_clause)) {
888 + if (!empty($where_clause)) {
889 + $where_clause .= ' AND (' . $search_clause . ')';
890 + } else {
891 + $where_clause = 'WHERE ' . $search_clause;
892 + }
893 + }
894 +
1145 895 $count_query = "
1146 896 SELECT COUNT($count_column) as total_count
1147 897 FROM {$from_clause}
1148 898 {$join_clauses}
@@ -1148,13 +898,13 @@
1148 898 {$join_clauses}
1149 899 {$where_clause}
1150 900 ";
1151 901
1152 - $total_count = $wpdb->get_var( $count_query );
902 + $total_count = $wpdb->get_var($count_query);
1153 903
1154 904 // If error occurred then throw new exception.
1155 - if ( $wpdb->last_error ) {
1156 - throw new \Exception( $wpdb->last_error );
905 + if ($wpdb->last_error) {
906 + throw new \Exception($wpdb->last_error);
1157 907 }
1158 908
1159 909 return (int) $total_count;
1160 910 }
@@ -1176,40 +926,56 @@
1176 926 * @throws \Exception Throw exception if error occurred during query execution.
1177 927 *
1178 928 * @return mixed Based on output param, default OBJECT.
1179 929 */
1180 - public static function get_all_with_search( string $table, array $where, array $search, string $order_by, $limit = 10, $offset = 0, string $order = 'DESC', string $output = 'OBJECT' ): array {
930 + public static function get_all_with_search(string $table, array $where, array $search, string $order_by, $limit = 10, $offset = 0, string $order = 'DESC', string $output = 'OBJECT'): array {
1181 931 global $wpdb;
1182 -
1183 - $table = self::prepare_table_name( $table );
1184 - $where_clause = self::prepare_where_search_clause( $where, $search, 'AND' );
1185 - $order_by_clause = self::prepare_order_clause( $order_by, $order );
1186 - $limit_clause = self::prepare_limit_clause( $limit, $offset );
1187 932
933 + $where_clause = !empty($where) ? 'WHERE ' . self::build_where_clause($where) : '';
934 + $search_clause = !empty($search) ? self::build_like_clause($search, 'AND') : '';
935 +
936 + if (!empty($search_clause)) {
937 + if (!empty($where_clause)) {
938 + $where_clause .= ' AND (' . $search_clause . ')';
939 + } else {
940 + $where_clause = 'WHERE ' . $search_clause;
941 + }
942 + }
943 +
944 + // Query to get total count
945 + $count_query = "
946 + SELECT COUNT(*)
947 + FROM {$table}
948 + {$where_clause}
949 + ";
950 + $total_count = $wpdb->get_var($count_query);
951 +
1188 952 // If error occurred then throw new exception.
1189 - if ( $wpdb->last_error ) {
1190 - throw new \Exception( $wpdb->last_error );
953 + if ($wpdb->last_error) {
954 + throw new \Exception($wpdb->last_error);
1191 955 }
1192 956
1193 - $query = "SELECT SQL_CALC_FOUND_ROWS *
957 + $query = $wpdb->prepare(
958 + "SELECT *
1194 959 FROM {$table}
1195 960 {$where_clause}
1196 - {$order_by_clause}
1197 - {$limit_clause}";
961 + ORDER BY {$order_by} {$order}
962 + LIMIT %d OFFSET %d",
963 + $limit,
964 + $offset
965 + );
1198 966
1199 - $results = $wpdb->get_results( $query, $output );
1200 - $has_records = is_array( $results ) && count( $results );
1201 - $total_count = $has_records ? (int) $wpdb->get_var( 'SELECT FOUND_ROWS()' ) : 0;
967 + $results = $wpdb->get_results($query, $output);
1202 968
1203 969 // If error occurred then throw new exception.
1204 - if ( $wpdb->last_error ) {
1205 - throw new \Exception( $wpdb->last_error );
970 + if ($wpdb->last_error) {
971 + throw new \Exception($wpdb->last_error);
1206 972 }
1207 973
1208 974 // Prepare response array.
1209 975 $response = array(
1210 - 'results' => $results,
1211 - 'total_count' => $total_count,
976 + 'results' => $results,
977 + 'total_count' => (int) $total_count,
1212 978 );
1213 979
1214 980 return $response;
1215 981 }
@@ -1230,9 +996,9 @@
1230 996 case 'today':
1231 997 $period_clause = "AND DATE($column) = CURDATE()";
1232 998 break;
1233 999 case 'monthly':
1234 - $period_clause = "AND MONTH($column) = MONTH(CURDATE()) AND YEAR($column) = YEAR(CURDATE())";
1000 + $period_clause = "AND MONTH($column) = MONTH(CURDATE())";
1235 1001 break;
1236 1002 case 'yearly':
1237 1003 $period_clause = "AND YEAR($column) = YEAR(CURDATE())";
1238 1004 break;
@@ -1307,14 +1073,13 @@
1307 1073 */
1308 1074 public static function duplicate_row( $table_name, array $where, ?callable $modifier = null ) {
1309 1075 global $wpdb;
1310 1076
1311 - $table_name = self::prepare_table_name( $table_name );
1312 1077 if ( empty( $where ) ) {
1313 1078 return new \WP_Error( 'missing_where', 'No WHERE condition provided.' );
1314 1079 }
1315 1080
1316 - $where_clause = self::prepare_where_clause( $where );
1081 + $where_clause = self::build_where_clause( $where );
1317 1082 $sql = $wpdb->prepare( "SELECT * FROM `$table_name` WHERE {$where_clause} LIMIT %d", 1 );
1318 1083 $row = $wpdb->get_row( $sql, ARRAY_A );
1319 1084
1320 1085 if ( ! $row ) {
@@ -1360,33 +1125,7 @@
1360 1125 * @return string
1361 1126 */
1362 1127 public static function get_valid_sort_order( $order ) {
1363 1128 return 'ASC' === strtoupper( $order ) ? 'ASC' : 'DESC';
1364 - }
1365 -
1366 - /**
1367 - * Get the schema of a database table.
1368 - *
1369 - * @since 3.8.1
1370 - *
1371 - * @param string $table_name The name of the database table.
1372 - *
1373 - * @throws \Exception Throws an exception if there is a database error.
1374 - *
1375 - * @return array Returns an array of table columns and their details.
1376 - */
1377 - public static function get_table_schema( $table_name) {
1378 -
1379 - global $wpdb;
1380 -
1381 - $result = $wpdb->get_results( "DESCRIBE {$table_name}", ARRAY_A );
1382 -
1383 - // If error occurred then throw new exception.
1384 - if ($wpdb->last_error) {
1385 - throw new \Exception($wpdb->last_error);
1386 - }
1387 -
1388 -
1389 - return $result;
1390 1129 }
1391 1130
1392 1131 }