AbstractProductListBlock.php
2 months ago
ProductListBlock.php
2 months ago
ProductPageBlock.php
2 months ago
ProductReviewBlock.php
4 months ago
ProductReviewListBlock.php
4 months ago
RelatedProductsBlock.php
2 months ago
ProductReviewListBlock.php
184 lines
| 1 | <?php |
| 2 | |
| 3 | namespace SureCart\Models\Blocks; |
| 4 | |
| 5 | use SureCart\Models\Review; |
| 6 | |
| 7 | /** |
| 8 | * The product review list block. |
| 9 | */ |
| 10 | class ProductReviewListBlock extends AbstractProductListBlock { |
| 11 | /** |
| 12 | * Product ID. |
| 13 | * |
| 14 | * @var string |
| 15 | */ |
| 16 | public $product_id; |
| 17 | |
| 18 | /** |
| 19 | * The collection result. |
| 20 | * |
| 21 | * @var \SureCart\Models\Collection |
| 22 | */ |
| 23 | protected $collection; |
| 24 | |
| 25 | /** |
| 26 | * Constructor. |
| 27 | * |
| 28 | * @param \WP_Block $block The block. |
| 29 | * @param string $product_id The product ID. |
| 30 | */ |
| 31 | public function __construct( \WP_Block $block, $product_id = null ) { |
| 32 | $this->block = $block; |
| 33 | $this->url = \SureCart::block()->urlParams( 'reviews' ); |
| 34 | $this->product_id = $product_id ?? ( $block->context['postId'] ?? null ); |
| 35 | } |
| 36 | |
| 37 | /** |
| 38 | * Get the query context. |
| 39 | * |
| 40 | * @return array |
| 41 | */ |
| 42 | public function getQueryContext() { |
| 43 | return $this->block->context['query'] ?? []; |
| 44 | } |
| 45 | |
| 46 | /** |
| 47 | * Build the query |
| 48 | * |
| 49 | * @return $this |
| 50 | */ |
| 51 | public function parse_query() { |
| 52 | $query = $this->getQueryContext(); |
| 53 | |
| 54 | // pagination. |
| 55 | $offset = absint( $query['offset'] ?? 0 ); |
| 56 | $per_page = $this->block->parsed_block['attrs']['query']['perPage'] |
| 57 | ?? $this->block->parsed_block['attrs']['limit'] |
| 58 | ?? $query['perPage'] |
| 59 | ?? 15; |
| 60 | |
| 61 | // order. |
| 62 | $url_order = $this->url->getArg( 'order' ); |
| 63 | $order = ! empty( $url_order ) ? sanitize_text_field( $url_order ) : ( $query['order'] ?? 'desc' ); |
| 64 | |
| 65 | // orderby. |
| 66 | $url_orderby = $this->url->getArg( 'orderby' ); |
| 67 | $orderby = ! empty( $url_orderby ) ? sanitize_text_field( $url_orderby ) : ( $query['orderBy'] ?? 'date' ); |
| 68 | |
| 69 | // page. |
| 70 | $page = $this->url->getCurrentPage(); |
| 71 | |
| 72 | $args = array( |
| 73 | 'status[]' => 'published', |
| 74 | 'product_ids[]' => [ $this->product_id ], |
| 75 | ); |
| 76 | |
| 77 | // Filter by star ratings if provided. |
| 78 | $stars_filter = $this->url->getArg( 'ratings' ); |
| 79 | if ( ! empty( $stars_filter ) ) { |
| 80 | $stars = is_array( $stars_filter ) ? $stars_filter : [ $stars_filter ]; |
| 81 | |
| 82 | foreach ( $stars as $star ) { |
| 83 | if ( (int) $star >= 1 && (int) $star <= 5 ) { |
| 84 | $args['stars'][] = (int) $star; |
| 85 | } |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | if ( $orderby && in_array( $orderby, [ 'stars', 'created_at', 'updated_at' ], true ) ) { |
| 90 | $args['sort'] = $orderby . ':' . $order; |
| 91 | } |
| 92 | |
| 93 | // Pagination. |
| 94 | $args['limit'] = $per_page; |
| 95 | $args['offset'] = ( $page - 1 ) * $per_page + $offset; |
| 96 | |
| 97 | $this->collection = Review::where( $args ) |
| 98 | ->with( [ 'customer' ] ) |
| 99 | ->paginate( |
| 100 | [ |
| 101 | 'page' => $page, |
| 102 | 'per_page' => $per_page, |
| 103 | ] |
| 104 | ); |
| 105 | |
| 106 | return $this; |
| 107 | } |
| 108 | |
| 109 | /** |
| 110 | * Offset the found posts. |
| 111 | * See: https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination |
| 112 | * |
| 113 | * @param int $found_posts The found posts. |
| 114 | * |
| 115 | * @return int The found posts with offset. |
| 116 | */ |
| 117 | public function offsetFoundPosts( $found_posts ) { |
| 118 | $query = $this->getQueryContext(); |
| 119 | $offset = absint( $query['offset'] ?? 0 ); |
| 120 | |
| 121 | return $found_posts - $offset; |
| 122 | } |
| 123 | |
| 124 | /** |
| 125 | * Run the query |
| 126 | * |
| 127 | * @return $this|\WP_Error |
| 128 | */ |
| 129 | public function query() { |
| 130 | return $this->parse_query(); |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | * Magic getter for pagination properties. |
| 135 | * |
| 136 | * @param string $key The property key. |
| 137 | * @return mixed |
| 138 | */ |
| 139 | public function __get( $key ) { |
| 140 | // Handle collection data access. |
| 141 | if ( 'data' === $key && $this->collection ) { |
| 142 | return $this->collection->data ?? []; |
| 143 | } |
| 144 | |
| 145 | // Handle max_num_pages for pagination. |
| 146 | if ( 'max_num_pages' === $key && $this->collection ) { |
| 147 | $pagination = $this->collection->pagination ?? new \stdClass(); |
| 148 | $count = $pagination->count ?? 0; |
| 149 | $limit = $pagination->limit ?? 1; |
| 150 | $pages = $limit > 0 ? (int) ceil( $count / $limit ) : 1; |
| 151 | return $pages; |
| 152 | } |
| 153 | |
| 154 | // Handle paged (current page). |
| 155 | if ( 'paged' === $key && $this->collection ) { |
| 156 | $pagination = $this->collection->pagination ?? new \stdClass(); |
| 157 | return $pagination->page ?? 1; |
| 158 | } |
| 159 | |
| 160 | // Handle found_posts. |
| 161 | if ( 'found_posts' === $key && $this->collection ) { |
| 162 | $pagination = $this->collection->pagination ?? new \stdClass(); |
| 163 | return $pagination->count ?? 0; |
| 164 | } |
| 165 | |
| 166 | // Handle has_pagination specifically for collection-based queries. |
| 167 | if ( 'has_pagination' === $key && $this->collection ) { |
| 168 | $max_page = $this->getQueryAttribute( 'pages', 0 ); |
| 169 | |
| 170 | // if the max page is 1, we don't have a next page. |
| 171 | if ( 1 === $max_page ) { |
| 172 | return false; |
| 173 | } |
| 174 | |
| 175 | $max_num_pages = $this->__get( 'max_num_pages' ); |
| 176 | $result = $max_num_pages > 1; |
| 177 | return $result; |
| 178 | } |
| 179 | |
| 180 | // Delegate to parent for other properties. |
| 181 | return parent::__get( $key ); |
| 182 | } |
| 183 | } |
| 184 |