PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.3
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.3
1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk All 48 releases
fluent-cart / app / Modules / Templating / TemplateActions.php

TemplateActions.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.3, at app/Modules/Templating/TemplateActions.php

336 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Modules\Templating;
4
5 use FluentCart\Api\Resource\ShopResource;
6 use FluentCart\Api\StoreSettings;
7 use FluentCart\Api\Taxonomy;
8 use FluentCart\App\CPT\FluentProducts;
9 //use FluentCart\App\Hooks\Handlers\ShortCodes\Buttons\AddToCartShortcode;
10 use FluentCart\App\Hooks\Handlers\ShortCodes\SingleProductShortCode;
11 use FluentCart\App\Modules\Data\ProductDataSetup;
12 use FluentCart\App\Modules\Data\ProductQuery;
13 use FluentCart\App\Services\Renderer\ProductListRenderer;
14 use FluentCart\App\Services\Renderer\ProductRenderer;
15 use FluentCart\App\Services\Renderer\ShopAppRenderer;
16 use FluentCart\App\Services\TemplateService;
17 use FluentCart\Framework\Support\Arr;
18
19 class TemplateActions
20 {
21 public function register()
22 {
23 add_action('fluent_cart/template/main_content', [$this, 'renderMainContent']);
24 add_action('fluent_cart/template/product_archive', [$this, 'renderProductArchive']);
25 add_action('fluent_cart/product/render_product_header', [$this, 'renderProductHeader']);
26
27 // Universal hook for after_product_content — fires on both classic and block themes
28 // Block themes render <!-- wp:post-content --> which runs the_content filter
29 add_filter('the_content', function ($content) {
30 if (!is_singular('fluent-products')) {
31 return $content;
32 }
33
34 global $post;
35
36 if (!$post || $post->post_type !== FluentProducts::CPT_NAME) {
37 return $content;
38 }
39
40 ob_start();
41 do_action('fluent_cart/product/after_product_content', $post->ID);
42 $extra = ob_get_clean();
43
44 if ($extra) {
45 $content .= $extra;
46 }
47
48 return $content;
49 }, 999);
50
51 add_shortcode('fluent_cart_product_header', function ($atts = []) {
52 $atts = shortcode_atts([
53 'id' => 0,
54 ], $atts);
55
56 $productId = absint($atts['id']);
57
58 if (!$productId) {
59 $productId = get_the_ID();
60 }
61
62 if (!$productId) {
63 return 'Product ID not found';
64 }
65
66 $product = ProductDataSetup::getProductModel($productId);
67 if (!$product || !$product->detail) {
68 return 'Product not found';
69 }
70
71 ob_start();
72 $this->renderProductHeader($product->ID);
73 $content = ob_get_clean();
74
75 return $this->tempFixShortcodeContent($content);
76 });
77
78 add_shortcode('fluent_cart_related_products', function ($atts = []) {
79 $atts = shortcode_atts([
80 'id' => 0,
81 ], $atts);
82
83 $productId = absint($atts['id']);
84
85 if (!$productId) {
86 $productId = get_the_ID();
87 }
88
89 if (!$productId) {
90 return __('Product ID not found', 'fluent-cart');
91 }
92
93 $product = ProductDataSetup::getProductModel($productId);
94 if (!$product || !$product->detail) {
95 return __('Product not found', 'fluent-cart');
96 }
97
98
99 $products = ShopResource::getSimilarProducts($productId, false);
100 if (empty($products)) {
101 return '';
102 }
103
104 ob_start();
105 (new ProductListRenderer(
106 $products,
107 __('Related Products', 'fluent-cart'),
108 'fct-similar-product-list-container'
109 ))->render();
110
111 $content = ob_get_clean();
112
113 return $this->tempFixShortcodeContent($content);
114 });
115
116 add_action('fluent_cart/template/before_content', [$this, 'renderArchiveHeader']);
117
118 }
119
120 public function renderMainContent()
121 {
122 $isTaxPages = is_tax(get_object_taxonomies('fluent-products'));
123 if ($isTaxPages) {
124 do_action('fluent_cart/template/product_archive');
125 }
126 }
127
128 public function renderArchiveHeader()
129 {
130 if (TemplateService::getCurrentFcPageType() !== 'product_taxonomy') {
131 return;
132 }
133
134 ?>
135 <div class="fct-archive-header-wrap">
136 <h1 class="fct-archive-title">
137 <?php
138 $queried_object = get_queried_object();
139 if ($queried_object && !empty($queried_object->name)) {
140 echo esc_html($queried_object->name);
141 } else {
142 echo esc_html(get_the_archive_title());
143 }
144 ?>
145 </h1>
146 <?php
147 $termDescription = term_description();
148 if ($termDescription) {
149 ?>
150 <div class="fct-archive-description">
151 <?php echo wp_kses_post(wpautop($termDescription)); ?>
152 </div>
153 <?php
154 }
155 ?>
156 </div>
157 <?php
158
159 }
160
161 public function renderProductArchive()
162 {
163 $queried_object = get_queried_object();
164
165 if (empty($queried_object->taxonomy) || !is_tax(get_object_taxonomies('fluent-products'))) {
166 return;
167 }
168
169 $productsQuery = (new ProductQuery([
170 'is_main_query' => true,
171 'paginate' => 'simple',
172 'with' => ['detail', 'variants']
173 ]));
174
175 $publicTaxonomies = Taxonomy::getTaxonomies();
176
177
178 unset($publicTaxonomies[$queried_object->taxonomy]);
179
180 $connectedTerms = $productsQuery->getConnectedTerms(array_values($publicTaxonomies), true);
181 //TODO: also add the child terms
182 $taxFilters = [];
183
184 foreach ($connectedTerms as $taxonomyName => $term) {
185
186 $taxObj = get_taxonomy($taxonomyName);
187 if (!$taxObj) {
188 continue;
189 }
190
191 $taxFilters[$taxonomyName] = [
192 'options' => $term['terms'],
193 'term' => $taxonomyName,
194 'label' => $taxObj->label
195 ];
196 }
197
198 $products = $productsQuery->get();
199 (new ShopAppRenderer($products, [
200 'default_filters' => $productsQuery->getDefaultFilters(),
201 'custom_filters' => [
202 'taxonomies' => [
203 $taxFilters
204 ],
205 'search' => true,
206 'price_range' => true,
207 ],
208 'pagination_type' => 'simple'
209 ]))->render();
210 }
211
212 public function initSingleProductHooks()
213 {
214 add_filter('the_title', function ($title, $post_id) {
215 if (apply_filters('fluent_cart/disable_auto_single_product_page', false)) {
216 return $title;
217 }
218
219 global $post;
220 global $wp_query;
221
222 if (
223 // this is the main query for a single product page
224 $wp_query->is_main_query()
225 // post_id is get_queried id
226 && $post_id == $wp_query->get_queried_object_id()
227 && $post->post_type === FluentProducts::CPT_NAME
228 ) {
229 return '';
230 }
231
232 return $title;
233 }, 10, 2);
234 add_filter('get_the_excerpt', function ($excerpt, $post) {
235 if (apply_filters('fluent_cart/disable_auto_single_product_page', false)) {
236 return $excerpt;
237 }
238
239 global $wp_query;
240
241 if (
242 $wp_query->is_main_query()
243 && $post->ID == $wp_query->get_queried_object_id()
244 && $post->post_type === FluentProducts::CPT_NAME
245 ) {
246 return '';
247 }
248
249 return $excerpt;
250 }, 10, 2);
251
252 add_filter('the_content', [$this, 'filterSingleProductContent'], 999);
253 }
254
255 public function filterSingleProductContent($content)
256 {
257 if (apply_filters('fluent_cart/disable_auto_single_product_page', false)) {
258 return $content;
259 }
260
261 global $post;
262 global $wp_query;
263
264 if (!$wp_query->is_main_query() && $post->post_type !== FluentProducts::CPT_NAME) {
265 return $content;
266 }
267
268 remove_filter('the_content', [$this, 'filterSingleProductContent']);
269 ob_start();
270 do_action('fluent_cart/product/render_product_header', $post->ID);
271 $headerContent = ob_get_clean();
272 $content = $headerContent . $content;
273
274 $storeSettings = new StoreSettings();
275
276 $showRelevant = $storeSettings->get('show_relevant_product_in_single_page') == 'yes';
277 $showRelevant = apply_filters('fluent_cart/single_product_page/show_relevant_products', $showRelevant, $post->ID);
278 if ($showRelevant) {
279 $products = ShopResource::getSimilarProducts($post->ID, false);
280 ob_start();
281 (new ProductListRenderer(
282 $products,
283 __('Related Products', 'fluent-cart'),
284 'fct-similar-product-list-container'
285 ))->render();
286
287 $relevantProducts = ob_get_clean();
288 $content .= $relevantProducts;
289 }
290
291 return $content;
292 }
293
294 public function renderProductHeader($productId = false)
295 {
296 if (!$productId) {
297 $productId = get_the_ID();
298 }
299
300 if (!$productId) {
301 return;
302 }
303
304 $product = ProductDataSetup::getProductModel($productId);
305 if (!$product || !$product->detail) {
306 return;
307 }
308
309 $storeSettings = new StoreSettings();
310 (new ProductRenderer($product, [
311 'view_type' => $storeSettings->get('variation_view', 'both'),
312 'column_type' => $storeSettings->get('variation_columns', 'masonry')
313 ]))->render();
314 }
315
316 private function tempFixShortcodeContent($content)
317 {
318
319 if (!$content) {
320 return $content;
321 }
322
323 // Remove empty <p> tags (including those with whitespace), <br> tags, and new lines
324 $cleaned = preg_replace([
325 '/<p>\s*<\/p>/i', // Remove empty <p> tags
326 '/<p>\s*<br\s*\/?>\s*<\/p>/i', // Remove <p> tags containing only <br>
327 '/<br\s*\/?>/i', // Remove all <br> tags
328 '/[\r\n]+/' // Remove all new lines
329 ], '', $content);
330
331 // Remove extra whitespace between tags to clean up the output
332 return preg_replace('/>\s+</', '><', $cleaned);
333 }
334
335 }
336