PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 2.2.0
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v2.2.0
2.3.0 2.2.0 2.1.1 2.1.0 2.0.0 1.10.0 1.9.1 1.9.0 1.2.1 1.2.2 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 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 All 59 releases
storeengine / includes / shortcode / products.php

products.php in StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More 2.2.0, at includes/shortcode/products.php

231 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace StoreEngine\Shortcode;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit;
7 }
8
9 use StoreEngine\Utils\Helper;
10 use StoreEngine\Utils\Template;
11 use WP_Term;
12
13 class Products {
14 public function __construct() {
15 add_shortcode( 'storeengine_products', [ $this, 'render_products' ] );
16 }
17
18 public function render_products( $atts, $content = '' ): string {
19 $products_per_row = Helper::get_settings( 'product_archive_products_per_row', (object) [
20 'desktop' => 3,
21 'tablet' => 2,
22 'mobile' => 1,
23 ] );
24
25 if ( isset( $_GET['orderby'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
26 $orderby = sanitize_text_field( wp_unslash( $_GET['orderby'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
27 } else {
28 $orderby = Helper::get_settings( 'product_archive_products_order', '' );
29 }
30
31 $atts = shortcode_atts( [
32 'ids' => '',
33 'exclude_ids' => '',
34 'category' => '',
35 'cat_not_in' => '',
36 'tag' => '',
37 'tag_not_in' => '',
38 'course_level' => '',
39 'price_type' => '',
40 'orderby' => $orderby,
41 'order' => '',
42 'count' => (int) Helper::get_settings( 'product_archive_products_per_page' ) ?? 12,
43 'column_per_row' => (int) $products_per_row->desktop ?? 3,
44 'has_pagination' => false,
45 ], $atts, 'storeengine_products' );
46
47 // Query Args.
48 $args = [
49 'post_type' => Helper::PRODUCT_POST_TYPE,
50 'post_status' => 'publish',
51 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
52 'relation' => 'OR',
53 [
54 'key' => '_storeengine_product_hide',
55 'value' => true,
56 'compare' => 'NOT EXISTS',
57 ],
58 [
59 'key' => '_storeengine_product_hide',
60 'value' => true,
61 'compare' => '!=',
62 ],
63 ],
64 ];
65
66 if ( ! empty( $atts['ids'] ) ) {
67 $args['post__in'] = (array) explode( ',', $atts['ids'] );
68 }
69
70 if ( ! empty( $atts['exclude_ids'] ) ) {
71 $args['post__not_in'] = (array) explode( ',', $atts['exclude_ids'] ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query, WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in
72 }
73
74 // taxonomy
75 $tax_query = [];
76 if ( ! empty( $atts['category'] ) ) {
77 $category = (array) explode( ',', $atts['category'] );
78 if ( ! empty( $category ) ) {
79 $tax_query[] = [
80 'taxonomy' => Helper::PRODUCT_CATEGORY_TAXONOMY,
81 'field' => 'term_id',
82 'terms' => $category,
83 'operator' => 'IN',
84 ];
85 }
86 } elseif ( is_tax( Helper::PRODUCT_CATEGORY_TAXONOMY ) ) {
87 $tax_query[] = [
88 'taxonomy' => Helper::PRODUCT_CATEGORY_TAXONOMY,
89 'field' => 'term_id',
90 'terms' => [ get_queried_object_id() ],
91 'operator' => 'IN',
92 ];
93 }
94
95 if ( ! empty( $atts['cat_not_in'] ) ) {
96 $cat_not_in = (array) explode( ',', $atts['cat_not_in'] );
97 if ( ! empty( $cat_not_in ) ) {
98 $tax_query[] = [
99 'taxonomy' => Helper::PRODUCT_CATEGORY_TAXONOMY,
100 'field' => 'term_id',
101 'terms' => $cat_not_in,
102 'operator' => 'NOT IN',
103 ];
104 }
105 }
106
107 if ( ! empty( $atts['tag'] ) ) {
108 $tag = (array) explode( ',', $atts['tag'] );
109 if ( ! empty( $tag ) ) {
110 $tax_query[] = [
111 'taxonomy' => Helper::PRODUCT_TAG_TAXONOMY,
112 'field' => 'term_id',
113 'terms' => $tag,
114 'operator' => 'IN',
115 ];
116 }
117 } elseif ( is_tax( Helper::PRODUCT_TAG_TAXONOMY ) ) {
118 $tax_query[] = [
119 'taxonomy' => Helper::PRODUCT_TAG_TAXONOMY,
120 'field' => 'term_id',
121 'terms' => [ get_queried_object_id() ],
122 'operator' => 'IN',
123 ];
124 }
125
126 if ( ! empty( $atts['tag_not_in'] ) ) {
127 $tag_not_in = (array) explode( ',', $atts['tag_not_in'] );
128 if ( ! empty( $tag_not_in ) ) {
129 $tax_query[] = [
130 'taxonomy' => Helper::PRODUCT_TAG_TAXONOMY,
131 'field' => 'term_id',
132 'terms' => $tag_not_in,
133 'operator' => 'NOT IN',
134 ];
135 }
136 }
137
138 if ( count( $tax_query ) > 0 ) {
139 if ( count( $tax_query ) > 1 ) {
140 $tax_query['relation'] = 'AND';
141 }
142
143 $args['tax_query'] = $tax_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
144 }
145
146 $args['order'] = ! empty( $atts['order'] ) ? $atts['order'] : 'DESC';
147 if ( ! empty( $atts['orderby'] ) && empty( $atts['order'] ) ) {
148 switch ( $atts['orderby'] ) {
149 case 'title':
150 $args['orderby'] = 'post_title';
151 $args['order'] = 'ASC';
152 break;
153 case 'date':
154 $args['orderby'] = 'publish_date';
155 $args['order'] = 'DESC';
156 break;
157 case 'modified':
158 $args['orderby'] = 'modified';
159 break;
160 case '':
161 default:
162 $args['orderby'] = 'ID';
163 }
164 }
165
166 $args['posts_per_page'] = (int) $atts['count'];
167
168 $grid_class = Helper::get_responsive_column( [
169 'desktop' => (int) $atts['column_per_row'],
170 'tablet' => 2,
171 'mobile' => 1,
172 ] );
173
174 $attr_str = '';
175 foreach (
176 [
177 'column_per_row',
178 'exclude_ids',
179 'ids',
180 'count',
181 'order',
182 'orderby',
183 'category',
184 'cat_not_in',
185 'tag',
186 'tag_not_in',
187 ] as $attribute
188 ) {
189 if ( ! empty( $atts[ $attribute ] ) ) {
190 $attribute = 'column_per_row' === $atts[ $attribute ] ? 'per_row' : $attribute;
191 $attribute = 'tag' === $atts[ $attribute ] ? 'tags' : $attribute;
192 // Add to data attribute string.
193 $attr_str .= ' data-' . esc_attr( $attribute ) . '="' . esc_attr( $atts[ $attribute ] ) . '"';
194 }
195 }
196
197 // @TODO use new WP_Query or override the default query with action/filter hook.
198 wp_reset_query(); // phpcs:ignore WordPress.WP.DiscouragedFunctions.wp_reset_query_wp_reset_query -- using post_query function directly.
199 // phpcs:ignore WordPress.WP.DiscouragedFunctions.query_posts_query_posts
200 query_posts( apply_filters( 'storeengine_products_shortcode_args', $args ) );
201
202 ob_start();
203
204 echo '<div class="storeengine-products storeengine-products--grid"' . $attr_str . '>'; //phpcs:ignore
205 echo '<div class="storeengine-products__body">';
206 echo '<div class="storeengine-row">';
207 if ( have_posts() ) {
208 // Load posts loop.
209 while ( have_posts() ) {
210 the_post();
211 Template::get_template( 'content-product.php', array( 'grid_class' => $grid_class ) );
212 }
213 wp_reset_postdata();
214 if ( $atts['has_pagination'] ) {
215 Template::get_template( 'archive/pagination.php' );
216 }
217 } else {
218 Template::get_template( 'archive/product-none.php' );
219 }
220
221 echo '</div>';
222 echo '</div>';
223 echo '</div>';
224
225 $output = ob_get_clean();
226 wp_reset_query(); // phpcs:ignore WordPress.WP.DiscouragedFunctions.wp_reset_query_wp_reset_query -- using post_query function directly.
227
228 return $output;
229 }
230 }
231