| @@ -32,9 +32,9 @@ | ||
| 32 | 32 | * @access public |
| 33 | 33 | * |
| 34 | 34 | * @var array |
| 35 | 35 | */ |
| 36 | - public $args = array(); | |
| 36 | + public $args = []; | |
| 37 | 37 | |
| 38 | 38 | /** |
| 39 | 39 | * The donors found based on the criteria set |
| 40 | 40 | * |
| @@ -42,9 +42,9 @@ | ||
| 42 | 42 | * @access public |
| 43 | 43 | * |
| 44 | 44 | * @var array |
| 45 | 45 | */ |
| 46 | - public $donors = array(); | |
| 46 | + public $donors = []; | |
| 47 | 47 | |
| 48 | 48 | /** |
| 49 | 49 | * The donors found based on the criteria set |
| 50 | 50 | * |
| @@ -75,8 +75,18 @@ | ||
| 75 | 75 | */ |
| 76 | 76 | public $meta_type = ''; |
| 77 | 77 | |
| 78 | 78 | /** |
| 79 | + * Preserve args | |
| 80 | + * | |
| 81 | + * @since 2.4.0 | |
| 82 | + * @access public | |
| 83 | + * | |
| 84 | + * @var array | |
| 85 | + */ | |
| 86 | + public $_args = []; | |
| 87 | + | |
| 88 | + /** | |
| 79 | 89 | * Default query arguments. |
| 80 | 90 | * |
| 81 | 91 | * Not all of these are valid arguments that can be passed to WP_Query. The ones that are not, are modified before |
| 82 | 92 | * the query is run to convert them to the proper syntax. |
| @@ -85,10 +95,10 @@ | ||
| 85 | 95 | * @access public |
| 86 | 96 | * |
| 87 | 97 | * @param $args array The array of arguments that can be passed in and used for setting up this payment query. |
| 88 | 98 | */ |
| 89 | - public function __construct( $args = array() ) { | |
| 90 | - $defaults = array( | |
| 99 | + public function __construct( $args = [] ) { | |
| 100 | + $defaults = [ | |
| 91 | 101 | 'number' => 20, |
| 92 | 102 | 'offset' => 0, |
| 93 | 103 | 'paged' => 1, |
| 94 | 104 | 'orderby' => 'id', |
| @@ -95,14 +105,16 @@ | ||
| 95 | 105 | 'order' => 'DESC', |
| 96 | 106 | 'user' => null, |
| 97 | 107 | 'email' => null, |
| 98 | 108 | 'donor' => null, |
| 99 | - 'meta_query' => array(), | |
| 100 | - 'date_query' => array(), | |
| 109 | + 'meta_query' => [], | |
| 110 | + 'date_query' => [], | |
| 101 | 111 | 's' => null, |
| 102 | 112 | 'fields' => 'all', // Supports donors (all fields) or valid column as string or array list. |
| 103 | 113 | 'count' => false, |
| 104 | - 'give_forms' => array(), | |
| 114 | + 'give_forms' => [], | |
| 115 | + 'start_date' => false, | |
| 116 | + 'end_date' => false, | |
| 105 | 117 | |
| 106 | 118 | /** |
| 107 | 119 | * donation_amount will contain value like: |
| 108 | 120 | * array( |
| @@ -111,16 +123,17 @@ | ||
| 111 | 123 | * ) |
| 112 | 124 | * |
| 113 | 125 | * You can also pass number value to this param then compare symbol will auto set to > |
| 114 | 126 | */ |
| 115 | - 'donation_amount' => array() | |
| 116 | - // 'form' => array(), | |
| 117 | - ); | |
| 127 | + 'donation_amount' => [], | |
| 128 | + ]; | |
| 118 | 129 | |
| 119 | - $this->args = wp_parse_args( $args, $defaults ); | |
| 130 | + $this->args = $this->_args = wp_parse_args( $args, $defaults ); | |
| 120 | 131 | $this->table_name = Give()->donors->table_name; |
| 121 | 132 | $this->meta_table_name = Give()->donor_meta->table_name; |
| 122 | 133 | $this->meta_type = Give()->donor_meta->meta_type; |
| 134 | + | |
| 135 | + $this->date_filter_pre(); | |
| 123 | 136 | } |
| 124 | 137 | |
| 125 | 138 | /** |
| 126 | 139 | * Modify the query/query arguments before we retrieve donors. |
| @@ -145,9 +158,9 @@ | ||
| 145 | 158 | * @access public |
| 146 | 159 | * |
| 147 | 160 | * @global wpdb $wpdb |
| 148 | 161 | * |
| 149 | - * @return array | |
| 162 | + * @return array|object|string|null | |
| 150 | 163 | */ |
| 151 | 164 | public function get_donors() { |
| 152 | 165 | global $wpdb; |
| 153 | 166 | |
| @@ -164,11 +177,12 @@ | ||
| 164 | 177 | |
| 165 | 178 | // Get donors from cache. |
| 166 | 179 | $this->donors = Give_Cache::get_db_query( $cache_key ); |
| 167 | 180 | |
| 168 | - if ( is_null( $this->donors ) ) { | |
| 181 | + if ( null === $this->donors ) { | |
| 169 | 182 | if ( empty( $this->args['count'] ) ) { |
| 170 | 183 | $this->donors = $wpdb->get_results( $this->get_sql() ); |
| 184 | + self::update_meta_cache( wp_list_pluck( (array) $this->donors, 'id' ) ); | |
| 171 | 185 | } else { |
| 172 | 186 | $this->donors = $wpdb->get_var( $this->get_sql() ); |
| 173 | 187 | } |
| 174 | 188 | |
| @@ -174,9 +188,8 @@ | ||
| 174 | 188 | |
| 175 | 189 | Give_Cache::set_db_query( $cache_key, $this->donors ); |
| 176 | 190 | } |
| 177 | 191 | |
| 178 | - | |
| 179 | 192 | /** |
| 180 | 193 | * Fires after retrieving donors. |
| 181 | 194 | * |
| 182 | 195 | * @since 1.8.14 |
| @@ -205,9 +218,8 @@ | ||
| 205 | 218 | } |
| 206 | 219 | |
| 207 | 220 | $where = $this->get_where_query(); |
| 208 | 221 | |
| 209 | - | |
| 210 | 222 | // Set offset. |
| 211 | 223 | if ( empty( $this->args['offset'] ) && ( 0 < $this->args['paged'] ) ) { |
| 212 | 224 | $this->args['offset'] = $this->args['number'] * ( $this->args['paged'] - 1 ); |
| 213 | 225 | } |
| @@ -344,17 +356,21 @@ | ||
| 344 | 356 | // Donors created for a specific date or in a date range |
| 345 | 357 | if ( ! empty( $this->args['date_query'] ) ) { |
| 346 | 358 | $date_query_object = new WP_Date_Query( is_array( $this->args['date_query'] ) ? $this->args['date_query'] : wp_parse_args( $this->args['date_query'] ), "{$this->table_name}.date_created" ); |
| 347 | 359 | |
| 348 | - $where .= str_replace( array( | |
| 349 | - "\n", | |
| 350 | - '( (', | |
| 351 | - '))', | |
| 352 | - ), array( | |
| 353 | - '', | |
| 354 | - '( (', | |
| 355 | - ') )', | |
| 356 | - ), $date_query_object->get_sql() ); | |
| 360 | + $where .= str_replace( | |
| 361 | + [ | |
| 362 | + "\n", | |
| 363 | + '( (', | |
| 364 | + '))', | |
| 365 | + ], | |
| 366 | + [ | |
| 367 | + '', | |
| 368 | + '( (', | |
| 369 | + ') )', | |
| 370 | + ], | |
| 371 | + $date_query_object->get_sql() | |
| 372 | + ); | |
| 357 | 373 | } |
| 358 | 374 | |
| 359 | 375 | return $where; |
| 360 | 376 | } |
| @@ -370,23 +386,33 @@ | ||
| 370 | 386 | */ |
| 371 | 387 | private function get_where_search() { |
| 372 | 388 | $where = ''; |
| 373 | 389 | |
| 390 | + // Bailout. | |
| 391 | + if ( empty( $this->args['s'] ) ) { | |
| 392 | + return $where; | |
| 393 | + } | |
| 394 | + | |
| 374 | 395 | // Donors created for a specific date or in a date range |
| 375 | - if ( ! empty( $this->args['s'] ) && false !== strpos( $this->args['s'], ':' ) ) { | |
| 396 | + if ( false !== strpos( $this->args['s'], ':' ) ) { | |
| 376 | 397 | $search_parts = explode( ':', $this->args['s'] ); |
| 377 | - | |
| 378 | 398 | if ( ! empty( $search_parts[0] ) ) { |
| 379 | 399 | switch ( $search_parts[0] ) { |
| 400 | + // Backward compatibility. | |
| 380 | 401 | case 'name': |
| 381 | 402 | $where = "AND {$this->table_name}.name LIKE '%{$search_parts[1]}%'"; |
| 382 | 403 | break; |
| 383 | - | |
| 384 | 404 | case 'note': |
| 385 | 405 | $where = "AND {$this->table_name}.notes LIKE '%{$search_parts[1]}%'"; |
| 386 | 406 | break; |
| 387 | 407 | } |
| 388 | 408 | } |
| 409 | + } elseif ( is_numeric( $this->args['s'] ) ) { | |
| 410 | + $where = "AND {$this->table_name}.id ='{$this->args['s']}'"; | |
| 411 | + | |
| 412 | + } else { | |
| 413 | + $search_field = is_email( $this->args['s'] ) ? 'email' : 'name'; | |
| 414 | + $where = "AND {$this->table_name}.$search_field LIKE '%{$this->args['s']}%'"; | |
| 389 | 415 | } |
| 390 | 416 | |
| 391 | 417 | return $where; |
| 392 | 418 | } |
| @@ -426,43 +452,49 @@ | ||
| 426 | 452 | */ |
| 427 | 453 | private function get_order_query() { |
| 428 | 454 | $table_columns = Give()->donors->get_columns(); |
| 429 | 455 | |
| 430 | - $query = array(); | |
| 456 | + $query = []; | |
| 431 | 457 | $ordersby = $this->args['orderby']; |
| 432 | 458 | |
| 433 | - if( ! is_array( $ordersby ) ) { | |
| 434 | - $ordersby = array( | |
| 435 | - $this->args['orderby'] => $this->args['order'] | |
| 436 | - ); | |
| 459 | + if ( ! is_array( $ordersby ) ) { | |
| 460 | + $ordersby = [ | |
| 461 | + $this->args['orderby'] => $this->args['order'], | |
| 462 | + ]; | |
| 437 | 463 | } |
| 438 | 464 | |
| 439 | 465 | // Remove non existing column. |
| 440 | 466 | // Filter orderby values. |
| 441 | 467 | foreach ( $ordersby as $orderby => $order ) { |
| 442 | - if( ! array_key_exists( $orderby, $table_columns ) ) { | |
| 443 | - unset( $ordersby[$orderby] ); | |
| 468 | + if ( ! array_key_exists( $orderby, $table_columns ) ) { | |
| 469 | + unset( $ordersby[ $orderby ] ); | |
| 470 | + continue; | |
| 444 | 471 | } |
| 445 | 472 | |
| 446 | 473 | $ordersby[ esc_sql( $orderby ) ] = esc_sql( $order ); |
| 447 | 474 | } |
| 448 | 475 | |
| 449 | - if( empty( $ordersby ) ) { | |
| 450 | - $ordersby = array( | |
| 451 | - 'id' => $this->args['order'] | |
| 452 | - ); | |
| 476 | + if ( empty( $ordersby ) ) { | |
| 477 | + $ordersby = [ | |
| 478 | + 'id' => $this->args['order'], | |
| 479 | + ]; | |
| 453 | 480 | } |
| 454 | 481 | |
| 455 | 482 | // Create query. |
| 456 | 483 | foreach ( $ordersby as $orderby => $order ) { |
| 484 | + /** | |
| 485 | + * @since 3.16.2 Prevent SQL Injection by not using the user defined order value directly in the query. | |
| 486 | + */ | |
| 487 | + $sanitizedOrder = $order === 'ASC' ? 'ASC' : 'DESC'; | |
| 488 | + | |
| 457 | 489 | switch ( $table_columns[ $orderby ] ) { |
| 458 | 490 | case '%d': |
| 459 | 491 | case '%f': |
| 460 | - $query[] = "{$this->table_name}.{$orderby}+0 {$order}"; | |
| 492 | + $query[] = "{$this->table_name}.{$orderby}+0 {$sanitizedOrder}"; | |
| 461 | 493 | break; |
| 462 | 494 | |
| 463 | 495 | default: |
| 464 | - $query[] = "{$this->table_name}.{$orderby} {$order}"; | |
| 496 | + $query[] = "{$this->table_name}.{$orderby} {$sanitizedOrder}"; | |
| 465 | 497 | } |
| 466 | 498 | } |
| 467 | 499 | |
| 468 | 500 | return ! empty( $query ) ? 'ORDER BY ' . implode( ', ', $query ) : ''; |
| @@ -469,8 +501,9 @@ | ||
| 469 | 501 | } |
| 470 | 502 | |
| 471 | 503 | /** |
| 472 | 504 | * Set donation count value where clause. |
| 505 | + * | |
| 473 | 506 | * @todo: add phpunit test |
| 474 | 507 | * |
| 475 | 508 | * @since 2.2.0 |
| 476 | 509 | * @access private |
| @@ -485,9 +518,9 @@ | ||
| 485 | 518 | $compare = '>'; |
| 486 | 519 | $amount = $this->args['donation_count']; |
| 487 | 520 | if ( is_array( $this->args['donation_count'] ) ) { |
| 488 | 521 | $compare = $this->args['donation_count'] ['compare']; |
| 489 | - $amount = $this->args['donation_count']['amount']; | |
| 522 | + $amount = $this->args['donation_count']['amount']; | |
| 490 | 523 | } |
| 491 | 524 | |
| 492 | 525 | $where .= "AND {$this->table_name}.purchase_count{$compare}{$amount}"; |
| 493 | 526 | } |
| @@ -496,8 +529,9 @@ | ||
| 496 | 529 | } |
| 497 | 530 | |
| 498 | 531 | /** |
| 499 | 532 | * Set purchase value where clause. |
| 533 | + * | |
| 500 | 534 | * @todo: add phpunit test |
| 501 | 535 | * |
| 502 | 536 | * @since 2.1.0 |
| 503 | 537 | * @access private |
| @@ -512,9 +546,9 @@ | ||
| 512 | 546 | $compare = '>'; |
| 513 | 547 | $amount = $this->args['donation_amount']; |
| 514 | 548 | if ( is_array( $this->args['donation_amount'] ) ) { |
| 515 | 549 | $compare = $this->args['donation_amount'] ['compare']; |
| 516 | - $amount = $this->args['donation_amount']['amount']; | |
| 550 | + $amount = $this->args['donation_amount']['amount']; | |
| 517 | 551 | } |
| 518 | 552 | |
| 519 | 553 | $where .= "AND {$this->table_name}.purchase_value{$compare}{$amount}"; |
| 520 | 554 | } |
| @@ -526,9 +560,11 @@ | ||
| 526 | 560 | * Set give_forms where clause. |
| 527 | 561 | * |
| 528 | 562 | * @todo : add phpunit test |
| 529 | 563 | * |
| 564 | + * @since 4.14.0 Replace {$wpdb->paymentmeta} with {$wpdb->donationmeta} | |
| 530 | 565 | * @since 2.1.0 |
| 566 | + * | |
| 531 | 567 | * @access private |
| 532 | 568 | * |
| 533 | 569 | * @global wpdb $wpdb |
| 534 | 570 | * @return string |
| @@ -551,9 +587,9 @@ | ||
| 551 | 587 | FROM {$wpdb->donationmeta} |
| 552 | 588 | WHERE meta_key=%s |
| 553 | 589 | AND {$donation_id_col} IN( |
| 554 | 590 | SELECT {$donation_id_col} |
| 555 | - FROM {$wpdb->paymentmeta} | |
| 591 | + FROM {$wpdb->donationmeta} | |
| 556 | 592 | WHERE meta_key=%s |
| 557 | 593 | AND meta_value IN (%s) |
| 558 | 594 | ) |
| 559 | 595 | ", |
| @@ -566,9 +602,9 @@ | ||
| 566 | 602 | |
| 567 | 603 | if ( ! empty( $donor_ids ) ) { |
| 568 | 604 | $donor_ids = wp_list_pluck( $donor_ids, 'donor_id' ); |
| 569 | 605 | $donor_ids = implode( ',', array_map( 'intval', $donor_ids ) ); |
| 570 | - $where .= "AND {$this->table_name}.id IN ({$donor_ids})"; | |
| 606 | + $where .= "AND {$this->table_name}.id IN ({$donor_ids})"; | |
| 571 | 607 | } else { |
| 572 | 608 | $where .= "AND {$this->table_name}.id IN ('0')"; |
| 573 | 609 | } |
| 574 | 610 | } |
| @@ -574,5 +610,84 @@ | ||
| 574 | 610 | } |
| 575 | 611 | |
| 576 | 612 | return $where; |
| 577 | 613 | } |
| 614 | + | |
| 615 | + /** | |
| 616 | + * If querying a specific date, add the proper filters. | |
| 617 | + * Note: This function currently only accept dates with admin defined core date format | |
| 618 | + * | |
| 619 | + * @since 2.4.0 | |
| 620 | + * @access public | |
| 621 | + * | |
| 622 | + * @return void | |
| 623 | + */ | |
| 624 | + public function date_filter_pre() { | |
| 625 | + if ( | |
| 626 | + ! empty( $this->args['date_query'] ) | |
| 627 | + || empty( $this->args['start_date'] ) | |
| 628 | + || empty( $this->args['end_date'] ) | |
| 629 | + ) { | |
| 630 | + return; | |
| 631 | + } | |
| 632 | + | |
| 633 | + $date_query = []; | |
| 634 | + | |
| 635 | + if ( ! empty( $this->args['start_date'] ) ) { | |
| 636 | + $date_query['after'] = date( | |
| 637 | + 'Y-m-d H:i:s', | |
| 638 | + is_numeric( $this->args['start_date'] ) | |
| 639 | + ? $this->args['start_date'] | |
| 640 | + : strtotime( $this->args['start_date'] ) | |
| 641 | + ); | |
| 642 | + } | |
| 643 | + | |
| 644 | + if ( ! empty( $this->args['end_date'] ) ) { | |
| 645 | + $date_query['before'] = date( | |
| 646 | + 'Y-m-d H:i:s', | |
| 647 | + is_numeric( $this->args['end_date'] ) | |
| 648 | + ? $this->args['end_date'] | |
| 649 | + : strtotime( $this->args['end_date'] ) | |
| 650 | + ); | |
| 651 | + } | |
| 652 | + | |
| 653 | + // Include Start Date and End Date while querying. | |
| 654 | + $date_query['inclusive'] = true; | |
| 655 | + | |
| 656 | + $this->__set( 'date_query', $date_query ); | |
| 657 | + } | |
| 658 | + | |
| 659 | + /** | |
| 660 | + * Update donors meta cache | |
| 661 | + * | |
| 662 | + * @since 2.5.0 | |
| 663 | + * @access private | |
| 664 | + * | |
| 665 | + * @param array $donor_ids | |
| 666 | + */ | |
| 667 | + public static function update_meta_cache( $donor_ids ) { | |
| 668 | + // Exit. | |
| 669 | + if ( empty( $donor_ids ) ) { | |
| 670 | + return; | |
| 671 | + } | |
| 672 | + | |
| 673 | + update_meta_cache( Give()->donor_meta->get_meta_type(), $donor_ids ); | |
| 674 | + } | |
| 675 | + | |
| 676 | + /** | |
| 677 | + * Set a query variable. | |
| 678 | + * | |
| 679 | + * @since 2.4.0 | |
| 680 | + * @access public | |
| 681 | + * | |
| 682 | + * @param $query_var | |
| 683 | + * @param $value | |
| 684 | + */ | |
| 685 | + public function __set( $query_var, $value ) { | |
| 686 | + if ( in_array( $query_var, [ 'meta_query', 'tax_query' ] ) ) { | |
| 687 | + $this->args[ $query_var ][] = $value; | |
| 688 | + } else { | |
| 689 | + $this->args[ $query_var ] = $value; | |
| 690 | + } | |
| 691 | + } | |
| 692 | + | |
| 578 | 693 | } |