PluginProbe ʕ •ᴥ•ʔ
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments / 3.0.3
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments v3.0.3
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
328 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']['query']['perPage'] ?? $this->block->parsed_block['attrs']['limit'] ?? $query['perPage'] ?? 15;
75 $order = ! empty( $this->url->getArg( 'order' ) )
76 ? sanitize_text_field( $this->url->getArg( 'order' ) )
77 : ( ! empty( $query['order'] ) ? $query['order'] : 'desc' );
78 $orderby = ! empty( $this->url->getArg( 'orderby' ) )
79 ? sanitize_text_field( $this->url->getArg( 'orderby' ) )
80 : ( ! empty( $query['orderBy'] ) ? $query['orderBy'] : 'date' );
81 $page = $this->url->getCurrentPage();
82
83 // build up the query.
84 $this->query_vars = array_filter(
85 array(
86 'post_type' => 'sc_product',
87 'post_status' => 'publish',
88 'ignore_sticky_posts' => 1,
89 'posts_per_page' => $per_page,
90 'offset' => ( $per_page * ( $page - 1 ) ) + $offset,
91 'paged' => (int) $this->url->getCurrentPage(),
92 'order' => $order,
93 'orderby' => $orderby,
94 's' => sanitize_text_field( $this->url->getArg( 'search' ) ),
95 )
96 );
97
98 // handle search.
99 if ( ! empty( $query['search'] ) && empty( $this->query_vars['s'] ) ) {
100 $this->query_vars['s'] = sanitize_text_field( $query['search'] );
101 }
102
103 // put together price query.
104 if ( 'price' === $this->url->getArg( 'orderby' ) ) {
105 $this->query_vars['meta_key'] = 'min_price_amount';
106 $this->query_vars['orderby'] = 'meta_value_num';
107 }
108
109 $tax_query = array(
110 'relation' => 'OR',
111 );
112
113 // handle tax query.
114 if ( ! empty( $query['taxQuery'] ) ) {
115 foreach ( $query['taxQuery'] as $taxonomy => $terms ) {
116 if ( is_taxonomy_viewable( $taxonomy ) && ! empty( $terms ) ) {
117 $tax_query[] = array(
118 'taxonomy' => sanitize_key( $taxonomy ),
119 'terms' => array_filter( array_map( 'absint', $terms ) ),
120 'include_children' => false,
121 );
122 }
123 }
124 }
125
126 // put together price query.
127 if ( 'price' === $orderby ) {
128 $this->query_vars['meta_key'] = 'min_price_amount';
129 $this->query_vars['orderby'] = 'meta_value_num';
130 }
131
132 $collection_id = sanitize_text_field( $this->block->context['surecart/product-list/collection_id'] ?? $this->block->parsed_block['attrs']['collection_id'] ?? '' );
133
134 // handle collection id send from "sc_product_collection" shortcode.
135 if ( ! empty( $collection_id ) ) {
136 $collection_ids = array_unique( array_map( 'sanitize_text_field', explode( ',', $collection_id ) ) );
137
138 $legacy_collection_ids = get_terms(
139 array(
140 'taxonomy' => 'sc_collection',
141 'field' => 'term_id',
142 'meta_query' => array(
143 array(
144 'key' => 'sc_id',
145 'value' => $collection_ids,
146 'compare' => 'IN',
147 ),
148 ),
149 )
150 ); // platform collection ids converted to WP taxonomy ids.
151
152 // only get the term_id.
153 $legacy_collection_ids = array_map(
154 function ( $term ) {
155 return $term->term_id;
156 },
157 $legacy_collection_ids
158 );
159
160 $tax_query[] =
161 array(
162 'taxonomy' => 'sc_collection',
163 'field' => 'term_id',
164 'terms' => array_unique( array_map( 'absint', $legacy_collection_ids ?? array() ) ),
165 );
166 } elseif ( is_tax() ) {
167 $term = get_queried_object();
168 $tax_query[] =
169 array(
170 'taxonomy' => 'sc_collection',
171 'field' => 'term_id',
172 'terms' => array_unique( array_map( 'absint', [ (int) $term->term_id ] ) ),
173 );
174 }
175
176 $all_taxonomies = $this->url->getAllTaxonomyArgs();
177
178 // handle taxonomies query.
179 foreach ( $all_taxonomies as $taxonomy => $terms ) {
180 $tax_query[] =
181 array(
182 'taxonomy' => $taxonomy,
183 'field' => 'slug',
184 'terms' => array_unique( array_map( 'strval', $terms ?? array() ) ),
185 'operator' => 'IN',
186 );
187 }
188
189 $this->query_vars['tax_query'][] = $tax_query;
190
191 // handle featured.
192 if ( 'featured' === ( $this->block->context['surecart/product-list/type'] ?? 'all' ) ) {
193 $this->query_vars['meta_query'] = [
194 [
195 'key' => 'featured',
196 'value' => '1',
197 'compare' => '=',
198 ],
199 ];
200 }
201
202 if ( 'custom' === ( $this->block->context['surecart/product-list/type'] ?? $this->block->parsed_block['attrs']['type'] ?? 'all' ) ) {
203 $query = $this->getQueryContext();
204 // backward compatibility.
205
206 $ids = ! empty( $query['include'] ) ? $query['include'] : ( ! empty( $this->block->context['surecart/product-list/ids'] ) ? $this->block->context['surecart/product-list/ids'] : ( ! empty( $this->block->parsed_block['attrs']['ids'] ) ? $this->block->parsed_block['attrs']['ids'] : [] ) );
207
208 // fallback for older strings - get the ids of legacy products.
209 $legacy_ids = [];
210 $ids_that_are_strings = array_map( 'sanitize_text_field', array_filter( $ids, 'is_string' ) );
211 if ( ! empty( $ids_that_are_strings ) ) {
212 $legacy_ids = get_posts(
213 [
214 'post_type' => 'sc_product',
215 'status' => 'publish',
216 'fields' => 'ids',
217 'posts_per_page' => -1,
218 'meta_query' => [
219 [
220 'key' => 'sc_id',
221 'value' => $ids_that_are_strings,
222 'compare' => 'IN',
223 ],
224 ],
225 ]
226 );
227 }
228
229 // get only ids that are integers.
230 $ids_that_are_integers = array_filter( $ids, 'is_int' );
231
232 // post in.
233 $this->query_vars['post__in'] = array_merge( $legacy_ids, $ids_that_are_integers );
234
235 // order by posts if there is not an order by.
236 if ( empty( $this->query_vars['orderby'] ) ) {
237 $this->query_vars['orderby'] = 'post__in';
238 }
239 }
240
241 return $this;
242 }
243
244 /**
245 * Offset the found posts.
246 * See: https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination
247 *
248 * @param int $found_posts The found posts.
249 *
250 * @return int The found posts with offset.
251 */
252 public function offsetFoundPosts( $found_posts ) {
253 $query = $this->getQueryContext();
254 $offset = absint( $query['offset'] ?? 0 );
255
256 return $found_posts - $offset;
257 }
258
259 /**
260 * Run the query
261 *
262 * @return $this|\WP_Error
263 */
264 public function query() {
265 $this->parse_query();
266 wp_reset_postdata();
267
268 add_filter( 'found_posts', [ $this, 'offsetFoundPosts' ], 1 );
269 $this->query = new \WP_Query( $this->query_vars );
270 remove_filter( 'found_posts', [ $this, 'offsetFoundPosts' ], 1 );
271
272 return $this;
273 }
274
275 /**
276 * Get the query attribute.
277 *
278 * @param string $key The key.
279 * @return \WP_Query
280 */
281 public function __get( $key ) {
282 // handle pagination.
283 if ( 'next_page_link' === $key ) {
284 return $this->max_num_pages && $this->max_num_pages !== $this->paged ? $this->url->addPageArg( $this->paged + 1 )->url() : '';
285 }
286
287 if ( 'previous_page_link' === $key ) {
288 return $this->paged > 1 ? $this->url->addPageArg( $this->paged - 1 )->url() : '';
289 }
290
291 if ( 'pagination_links' === $key ) {
292 return array_map(
293 function ( $i ) {
294 return array(
295 'href' => $this->url->addPageArg( $i )->url(),
296 'name' => $i,
297 'current' => (int) $i === (int) $this->paged,
298 );
299 },
300 range( 1, $this->max_num_pages )
301 );
302 }
303
304 if ( 'products' === $key ) {
305 return array_map(
306 function ( $post ) {
307 return sc_get_product( $post );
308 },
309 $this->query->posts
310 );
311 }
312
313 return $this->query->$key ?? $this->query->query[ $key ] ?? $this->query->query_vars[ $key ] ?? null;
314 }
315
316 /**
317 * Call the query method.
318 *
319 * @param string $method The method.
320 * @param array $args The arguments.
321 *
322 * @return mixed
323 */
324 public function __call( $method, $args ) {
325 return $this->query->$method( ...$args );
326 }
327 }
328