PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.7.1
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.7.1
1.7.1 1.7.0 1.6.6 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 All 51 releases
fluent-cart / app / Hooks / Handlers / BlockEditors / ProductReviewsBlockEditor.php

ProductReviewsBlockEditor.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.7.1, at app/Hooks/Handlers/BlockEditors/ProductReviewsBlockEditor.php

173 lines 5.8 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\Hooks\Handlers\BlockEditors;
4
5 use FluentCart\App\App;
6 use FluentCart\App\Modules\Templating\AssetLoader;
7 use FluentCart\App\Services\Renderer\ProductReviewRenderer;
8 use FluentCart\App\Services\Reviews\LayoutPresets;
9 use FluentCart\App\Services\Translations\TransStrings;
10 use FluentCart\Framework\Support\Arr;
11
12 class ProductReviewsBlockEditor extends BlockEditor
13 {
14 protected static string $editorName = 'product-reviews';
15
16 public function supports(): array
17 {
18 return [
19 'html' => false,
20 'align' => true,
21 'typography' => [
22 'fontSize' => true,
23 'lineHeight' => true,
24 '__experimentalFontFamily' => true,
25 '__experimentalFontWeight' => true,
26 '__experimentalDefaultControls' => [
27 'fontSize' => true,
28 ],
29 ],
30 'color' => [
31 'text' => true,
32 'background' => true,
33 ],
34 'spacing' => [
35 'margin' => true,
36 'padding' => true,
37 ],
38 '__experimentalBorder' => [
39 'color' => true,
40 'radius' => true,
41 'style' => true,
42 'width' => true,
43 ],
44 ];
45 }
46
47 /**
48 * Render children only inside renderContainer(), after setting product context.
49 * WordPress's initial pass would otherwise render them twice.
50 */
51 protected function skipInnerBlocks(): bool
52 {
53 return true;
54 }
55
56 /**
57 * This context key makes children inherit the container's product,
58 * overriding any saved child product selection without editor-side pinning.
59 */
60 public function provideContext()
61 {
62 return [
63 'fluent-cart/review_container_query' => 'query_type',
64 ];
65 }
66
67 public function blockAttributes(): array
68 {
69 return [
70 // Mirror the JS registration: WordPress drops attributes missing here before render.
71 'query_type' => ['type' => 'string', 'default' => 'default'],
72 'product_id' => ['type' => ['string', 'number'], 'default' => ''],
73 // Picker state only; the saved child blocks define the rendered layout.
74 'preset' => ['type' => 'string', 'default' => 'classic'],
75 ];
76 }
77
78 public function getScripts(): array
79 {
80 return [
81 [
82 'source' => 'admin/BlockEditor/ProductReviews/ProductReviewsBlockEditor.jsx',
83 'dependencies' => ['wp-blocks', 'wp-components', 'wp-data', 'wp-block-editor', 'wp-element']
84 ]
85 ];
86 }
87
88 public function getStyles(): array
89 {
90 return [
91 'admin/BlockEditor/ProductReviews/style/product-reviews-block-editor.scss'
92 ];
93 }
94
95 public function localizeData(): array
96 {
97 return [
98 $this->getLocalizationKey() => [
99 'slug' => $this->slugPrefix,
100 'name' => static::getEditorName(),
101 'title' => __('Product Reviews', 'fluent-cart'),
102 'description' => __('Display customer reviews and ratings for a product.', 'fluent-cart'),
103 // Gate preset insertion, not saved layouts or manual block composition.
104 'is_pro' => App::isProActive(),
105 // Share preset definitions with other block composers.
106 'presets' => LayoutPresets::all(),
107 ],
108 'fluent_cart_block_translation' => TransStrings::blockStrings(),
109 ];
110 }
111
112 public function render(array $shortCodeAttribute, $block = null)
113 {
114 $product = $this->resolveProduct($shortCodeAttribute);
115
116 if (!$product) {
117 return '';
118 }
119
120 AssetLoader::loadSingleProductAssets();
121
122 // Child blocks render within the resolved product context.
123 if ($block instanceof \WP_Block && !empty($block->inner_blocks)) {
124 return $this->renderContainer($shortCodeAttribute, $block, $product);
125 }
126
127 // Without children, use the shortcode's default section layout.
128 $wrapper_attributes = get_block_wrapper_attributes([
129 'class' => 'fct-product-reviews-block',
130 ]);
131
132 ob_start();
133 (new ProductReviewRenderer($product->ID, []))->render();
134 $inner = ob_get_clean();
135
136 return static::wrapUnlessEmpty($wrapper_attributes, $inner);
137 }
138
139 protected function renderContainer(array $shortCodeAttribute, \WP_Block $block, $product)
140 {
141 // setup_postdata() updates ProductDataSetup through the_post.
142 // Restore the outer product when nested; wp_reset_postdata() alone
143 // would give following siblings the main-query post instead.
144 $isCustom = Arr::get($shortCodeAttribute, 'query_type', 'default') === 'custom';
145 $previousProduct = $isCustom ? fluent_cart_get_current_product() : null;
146
147 if ($isCustom) {
148 setup_postdata($product->ID);
149 }
150
151 $innerContent = '';
152 foreach ($block->inner_blocks as $innerBlock) {
153 if (isset($innerBlock->parsed_block)) {
154 $innerContent .= $innerBlock->render();
155 }
156 }
157
158 if ($isCustom) {
159 if ($previousProduct) {
160 setup_postdata($previousProduct->ID);
161 } else {
162 wp_reset_postdata();
163 }
164 }
165
166 $wrapper_attributes = get_block_wrapper_attributes([
167 'class' => 'fct-product-reviews-block fct-product-reviews-container',
168 ]);
169
170 return static::wrapUnlessEmpty($wrapper_attributes, $innerContent);
171 }
172 }
173