PluginProbe ʕ •ᴥ•ʔ
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments / 3.0.0-beta2
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments v3.0.0-beta2
4.7.0 4.6.6 4.6.5 4.6.4 4.6.3 4.6.2 4.6.1 4.6.0 4.5.1 4.5.0 4.4.2 4.4.1 4.4.0 4.3.3 4.3.2 4.3.1 4.3.0 4.2.3 4.2.2 4.2.1 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.11.1 1.11.2 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.9.0 1.9.1 1.9.2 1.9.3 1.9.4 1.9.5 2.0.0 2.0.1 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.10.0 2.10.1 2.11.0 2.11.1 2.11.2 2.11.3 2.11.4 2.12.0 2.13.0 2.14.0 2.14.1 2.15.0 2.15.1 2.16.0 2.16.1 2.16.2 2.16.3 2.17.0 2.17.1 2.17.2 2.18.0 2.19.0 2.19.2 2.19.3 2.19.4 2.2.0 2.2.1 2.20.0 2.20.1 2.20.2 2.20.3 2.20.4 2.20.5 2.20.6 2.21.0 2.22.0 2.22.1 2.23.0 2.24.0 2.25.0 2.25.1 2.25.2 2.26.0 2.27.0 2.27.1 2.28.0 2.29.0 2.29.1 2.29.2 2.29.3 2.29.4 2.3.0 2.3.1 2.30.0 2.31.0 2.31.1 2.31.2 2.31.3 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.40.0 2.40.1 2.5.0 2.5.1 2.5.2 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.9.0 3.0.0 3.0.0-RC1 3.0.0-RC2 3.0.0-beta1 3.0.0-beta2 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.10.0 3.10.1 3.11.0 3.12.0 3.13.0 3.13.1 3.13.2 3.13.3 3.13.4 3.14.0 3.15.0 3.15.1 3.15.2 3.15.3 3.15.4 3.15.5 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.16.6 3.16.7 3.16.8 3.17.0 3.17.1 3.17.2 3.17.3 3.17.4 3.17.5 3.17.6 3.18.0 3.19.0 3.19.1 3.19.2 3.2.0 3.2.1 3.2.2 3.20.0 3.20.1 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 4.0.0 4.0.1 4.0.2 4.0.3 trunk 4.1.0 0.2.19.1 4.1.1 1.0.0 4.2.0 1.0.1 1.0.2
surecart / app / src / Models / Blocks / ProductListBlock.php
surecart / app / src / Models / Blocks Last commit date
ProductListBlock.php 1 year ago ProductPageBlock.php 1 year ago
ProductListBlock.php
306 lines
1 <?php
2
3 namespace SureCart\Models\Blocks;
4
5 /**
6 * The product list block.
7 */
8 class ProductListBlock {
9 /**
10 * The block.
11 *
12 * @var \WP_Block
13 */
14 protected $block;
15
16 /**
17 * The URL.
18 *
19 * @var object
20 */
21 protected $url;
22
23 /**
24 * The query vars.
25 *
26 * @var array
27 */
28 protected $query_vars = [];
29
30 /**
31 * The query.
32 *
33 * @var \WP_Query
34 */
35 protected $query;
36
37 /**
38 * Constructor.
39 *
40 * @param \WP_Block $block The block.
41 */
42 public function __construct( \WP_Block $block = null ) {
43 $this->block = $block ? $block : \WP_Block_Supports::$block_to_render;
44 $this->url = \SureCart::block()->urlParams( 'products' );
45 }
46
47 /**
48 * Get the URL.
49 *
50 * @return object|null
51 */
52 public function urlParams() {
53 return $this->url;
54 }
55
56 /**
57 * Get the query context.
58 *
59 * @return array
60 */
61 public function getQueryContext() {
62 return $this->block->context['query'] ?? [];
63 }
64
65 /**
66 * Build the query
67 *
68 * @return $this
69 */
70 public function parse_query() {
71 $query = $this->getQueryContext();
72
73 $offset = absint( $query['offset'] ?? 0 );
74 $per_page = $this->block->parsed_block['attrs']['limit'] ?? $this->block->context['surecart/product-list/limit'] ?? $query['perPage'] ?? 15;
75 $page = $this->url->getCurrentPage();
76
77 // build up the query.
78 $this->query_vars = array_filter(
79 array(
80 'post_type' => 'sc_product',
81 'post_status' => 'publish',
82 'ignore_sticky_posts' => 1,
83 'posts_per_page' => $per_page,
84 'offset' => ( $per_page * ( $page - 1 ) ) + $offset,
85 'paged' => (int) $this->url->getCurrentPage(),
86 'order' => sanitize_text_field( $this->url->getArg( 'order' ) ),
87 'orderby' => sanitize_text_field( $this->url->getArg( 'orderby' ) ),
88 's' => sanitize_text_field( $this->url->getArg( 'search' ) ),
89 )
90 );
91
92 // handle search.
93 if ( ! empty( $query['search'] ) && empty( $this->query_vars['s'] ) ) {
94 $this->query_vars['s'] = sanitize_text_field( $query['search'] );
95 }
96
97 // handle tax query.
98 if ( ! empty( $query['taxQuery'] ) ) {
99 $this->query_vars['tax_query'] = array();
100 foreach ( $query['taxQuery'] as $taxonomy => $terms ) {
101 if ( is_taxonomy_viewable( $taxonomy ) && ! empty( $terms ) ) {
102 $this->query_vars['tax_query'][] = array(
103 'taxonomy' => sanitize_key( $taxonomy ),
104 'terms' => array_filter( array_map( 'absint', $terms ) ),
105 'include_children' => false,
106 );
107 }
108 }
109 }
110
111 // put together price query.
112 if ( 'price' === $this->url->getArg( 'orderby' ) ) {
113 $this->query_vars['meta_key'] = 'min_price_amount';
114 $this->query_vars['orderby'] = 'meta_value_num';
115 }
116
117 $collection_id = sanitize_text_field( $this->block->context['surecart/product-list/collection_id'] ?? $this->block->parsed_block['attrs']['collection_id'] ?? '' );
118
119 $collection_ids_to_filter = array();
120
121 // handle collection id send from "sc_product_collection" shortcode.
122 if ( ! empty( $collection_id ) ) {
123 $collection_ids = array_unique( array_map( 'sanitize_text_field', explode( ',', $collection_id ) ) );
124
125 $legacy_collection_ids = get_terms(
126 array(
127 'taxonomy' => 'sc_collection',
128 'field' => 'term_id',
129 'meta_query' => array(
130 array(
131 'key' => 'sc_id',
132 'value' => $collection_ids,
133 'compare' => 'IN',
134 ),
135 ),
136 )
137 ); // platform collection ids converted to WP taxonomy ids.
138
139 // only get the term_id.
140 $legacy_collection_ids = array_map(
141 function ( $term ) {
142 return $term->term_id;
143 },
144 $legacy_collection_ids
145 );
146
147 $collection_ids_to_filter = array_merge( $legacy_collection_ids, $collection_ids_to_filter );
148 } elseif ( is_tax() ) {
149 $term = get_queried_object();
150 $collection_ids_to_filter = [ (int) $term->term_id ];
151 }
152
153 $new_collection_ids = $this->url->getArg( 'sc_collection' );
154
155 // handle collections query.
156 if ( ! empty( $new_collection_ids ) ) {
157 $collection_ids_to_filter = array_merge( $new_collection_ids, $collection_ids_to_filter );
158 }
159
160 if ( ! empty( $collection_ids_to_filter ) ) {
161 $this->query_vars['tax_query'] =
162 array(
163 array(
164 'taxonomy' => 'sc_collection',
165 'field' => 'term_id',
166 'terms' => array_unique( array_map( 'intval', $collection_ids_to_filter ?? array() ) ),
167 ),
168 );
169 }
170
171 // handle featured.
172 if ( 'featured' === ( $this->block->context['surecart/product-list/type'] ?? 'all' ) ) {
173 $this->query_vars['meta_query'] = [
174 [
175 'key' => 'featured',
176 'value' => '1',
177 'compare' => '=',
178 ],
179 ];
180 }
181
182 if ( 'custom' === ( $this->block->context['surecart/product-list/type'] ?? 'all' ) ) {
183 $query = $this->getQueryContext();
184 // backward compatibility.
185 $ids = $query['include'] ?? $this->block->context['surecart/product-list/ids'] ?? $this->block->parsed_block['attrs']['ids'] ?? [];
186 // fallback for older strings - get the ids of legacy products.
187 $legacy_ids = [];
188 $ids_that_are_strings = array_map( 'sanitize_text_field', array_filter( $ids, 'is_string' ) );
189 if ( ! empty( $ids_that_are_strings ) ) {
190 $legacy_ids = get_posts(
191 [
192 'post_type' => 'sc_product',
193 'status' => 'publish',
194 'fields' => 'ids',
195 'posts_per_page' => -1,
196 'meta_query' => [
197 [
198 'key' => 'sc_id',
199 'value' => $ids_that_are_strings,
200 'compare' => 'IN',
201 ],
202 ],
203 ]
204 );
205 }
206
207 // get only ids that are integers.
208 $ids_that_are_integers = array_filter( $ids, 'is_int' );
209
210 // post in.
211 $this->query_vars['post__in'] = array_merge( $legacy_ids, $ids_that_are_integers );
212
213 // order by posts if there is not an order by.
214 if ( empty( $this->query_vars['orderby'] ) ) {
215 $this->query_vars['orderby'] = 'post__in';
216 }
217 }
218
219 return $this;
220 }
221
222 /**
223 * Offset the found posts.
224 * See: https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination
225 *
226 * @param int $found_posts The found posts.
227 *
228 * @return int The found posts with offset.
229 */
230 public function offsetFoundPosts( $found_posts ) {
231 $query = $this->getQueryContext();
232 $offset = absint( $query['offset'] ?? 0 );
233
234 return $found_posts - $offset;
235 }
236
237 /**
238 * Run the query
239 *
240 * @return $this|\WP_Error
241 */
242 public function query() {
243 $this->parse_query();
244 wp_reset_postdata();
245
246 add_filter( 'found_posts', [ $this, 'offsetFoundPosts' ], 1 );
247 $this->query = new \WP_Query( $this->query_vars );
248 remove_filter( 'found_posts', [ $this, 'offsetFoundPosts' ], 1 );
249
250 return $this;
251 }
252
253 /**
254 * Get the query attribute.
255 *
256 * @param string $key The key.
257 * @return \WP_Query
258 */
259 public function __get( $key ) {
260 // handle pagination.
261 if ( 'next_page_link' === $key ) {
262 return $this->max_num_pages && $this->max_num_pages !== $this->paged ? $this->url->addPageArg( $this->paged + 1 )->url() : '';
263 }
264
265 if ( 'previous_page_link' === $key ) {
266 return $this->paged > 1 ? $this->url->addPageArg( $this->paged - 1 )->url() : '';
267 }
268
269 if ( 'pagination_links' === $key ) {
270 return array_map(
271 function ( $i ) {
272 return array(
273 'href' => $this->url->addPageArg( $i )->url(),
274 'name' => $i,
275 'current' => (int) $i === (int) $this->paged,
276 );
277 },
278 range( 1, $this->max_num_pages )
279 );
280 }
281
282 if ( 'products' === $key ) {
283 return array_map(
284 function ( $post ) {
285 return sc_get_product( $post );
286 },
287 $this->query->posts
288 );
289 }
290
291 return $this->query->$key ?? $this->query->query[ $key ] ?? $this->query->query_vars[ $key ] ?? null;
292 }
293
294 /**
295 * Call the query method.
296 *
297 * @param string $method The method.
298 * @param array $args The arguments.
299 *
300 * @return mixed
301 */
302 public function __call( $method, $args ) {
303 return $this->query->$method( ...$args );
304 }
305 }
306