PluginProbe
UiCore Elements – Free widgets and templates for Elementor / 1.3.17
UiCore Elements – Free widgets and templates for Elementor v1.3.17
1.3.17 1.3.16 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 All 41 releases
← All changes | includes/utils/meta-component.php +474 -214 1.0.141.3.17 View file →
@@ -1,5 +1,6 @@
1 1 <?php
2 +
2 3 namespace UiCoreElements\Utils;
3 4
4 5 use Elementor\Controls_Manager;
5 6 use Elementor\Group_Control_Typography;
@@ -4,13 +5,14 @@
4 5 use Elementor\Controls_Manager;
5 6 use Elementor\Group_Control_Typography;
6 7 use UiCoreElements\Helper;
7 8
8 -if ( ! defined( 'ABSPATH' ) ) {
9 - exit; // Exit if accessed directly
9 +if (! defined('ABSPATH')) {
10 + exit; // Exit if accessed directly
10 11 }
11 12
12 -trait Meta_Trait {
13 +trait Meta_Trait
14 +{
13 15
14 16 function get_meta_content_controls($product_metas = false)
15 17 {
16 18
@@ -15,34 +17,36 @@
15 17 {
16 18
17 19 // Meta options
18 20 $options = [
19 - 'none' => __( 'None', 'uicore-elements' ),
21 + 'none' => __('None', 'uicore-elements'),
20 22 ];
21 23 $generic_posts = [
22 - 'author' => __( 'Author', 'uicore-elements' ),
23 - 'date' => __( 'Posted Date', 'uicore-elements' ),
24 - 'updated date' => __( 'Updated Date', 'uicore-elements' ),
25 - 'comment' => __( 'Comments Count', 'uicore-elements' ),
26 - 'reading time' => __( 'Reading Time', 'uicore-elements' ),
27 - 'category' => __( 'Category', 'uicore-elements' ),
24 + 'author' => __('Author', 'uicore-elements'),
25 + 'date' => __('Posted Date', 'uicore-elements'),
26 + 'updated date' => __('Updated Date', 'uicore-elements'),
27 + 'comment' => __('Comments Count', 'uicore-elements'),
28 + 'reading time' => __('Reading Time', 'uicore-elements'),
29 + 'category' => __('Category', 'uicore-elements'),
30 + 'tag' => __('Tag', 'uicore-elements'),
31 + 'excerpt' => __('Excerpt', 'uicore-elements'),
28 32 ];
29 33 $products = [
30 - 'product price' => __( 'Product Price', 'uicore-elements' ),
31 - 'product rating' => __( 'Product Rating', 'uicore-elements' ),
32 - 'product stock' => __( 'Product Stock', 'uicore-elements' ),
33 - 'product category' => __( 'Product Category', 'uicore-elements' ),
34 - 'product tag' => __( 'Product Tag', 'uicore-elements' ),
35 - 'product attribute' => __( 'Product Attribute', 'uicore-elements' ),
36 - 'product sale' => __( 'Product Sale', 'uicore-elements' ),
34 + 'product price' => __('Product Price', 'uicore-elements'),
35 + 'product rating' => __('Product Rating', 'uicore-elements'),
36 + 'product stock' => __('Product Stock', 'uicore-elements'),
37 + 'product category' => __('Product Category', 'uicore-elements'),
38 + 'product tag' => __('Product Tag', 'uicore-elements'),
39 + 'product attribute' => __('Product Attribute', 'uicore-elements'),
40 + 'product sale' => __('Product Sale', 'uicore-elements'),
37 41 ];
38 42 $custom = [
39 - 'custom meta' => __( 'Custom Meta', 'uicore-elements' ),
40 - 'custom taxonomy' => __( 'Custom Taxonomy', 'uicore-elements' ),
41 - 'custom html' => __( 'Custom HTML', 'uicore-elements' ),
43 + 'custom meta' => __('Custom Meta', 'uicore-elements'),
44 + 'custom taxonomy' => __('Custom Taxonomy', 'uicore-elements'),
45 + 'custom html' => __('Custom HTML', 'uicore-elements'),
42 46 ];
43 47 $portfolio = [
44 - 'portfolio category' => __( 'Portfolio Category', 'uicore-elements' ),
48 + 'portfolio category' => __('Portfolio Category', 'uicore-elements'),
45 49 ];
46 50
47 51 $options = $product_metas ?
48 52 array_merge($options, $products, $custom) : // specific to product widgets
@@ -49,68 +53,146 @@
49 53 array_merge($options, $generic_posts, $products, $portfolio, $custom); // generic posts widgets
50 54
51 55
52 56 $repeater = new \Elementor\Repeater();
53 - $repeater->add_control('type',[
54 - 'label' => __( 'Meta', 'uicore-elements' ),
57 + $repeater->add_control(
58 + 'type',
59 + [
60 + 'label' => __('Meta', 'uicore-elements'),
55 61 'type' => Controls_Manager::SELECT,
56 62 'default' => '',
57 63 'options' => $options
58 64 ]
59 65 );
60 - $repeater->add_control('type_custom',[
61 - 'label' => __( 'Custom Field Name', 'uicore-elements' ),
62 - 'type' => Controls_Manager::TEXT,
63 - 'condition' => [
64 - 'type' => ['custom meta','custom taxonomy']
65 - ]
66 + $repeater->add_control(
67 + 'type_custom',
68 + [
69 + 'label' => __('Custom Field Name', 'uicore-elements'),
70 + 'type' => Controls_Manager::TEXT,
71 + 'condition' => [
72 + 'type' => ['custom meta', 'custom taxonomy']
66 73 ]
67 - );
68 - $repeater->add_control('html_custom',[
69 - 'label' => __( 'Custom HTML', 'uicore-elements' ),
70 - 'type' => Controls_Manager::TEXTAREA,
71 - 'condition' => [
72 - 'type' => ['custom html']
73 - ]
74 + ]
75 + );
76 + $repeater->add_control(
77 + 'html_custom',
78 + [
79 + 'label' => __('Custom HTML', 'uicore-elements'),
80 + 'type' => Controls_Manager::TEXTAREA,
81 + 'condition' => [
82 + 'type' => ['custom html']
74 83 ]
75 - );
76 - $repeater->add_control('date_format',[
77 - 'label' => esc_html__( 'Date Format', 'uicore-elements' ),
78 - 'type' => Controls_Manager::SELECT,
79 - 'default' => 'default',
80 - 'options' => [
81 - 'default' => esc_html__( 'Default', 'uicore-elements' ),
82 - 'F j, Y' => gmdate( 'F j, Y' ),
83 - 'Y-m-d' => gmdate( 'Y-m-d' ),
84 - 'm/d/Y' => gmdate( 'm/d/Y' ),
85 - 'd/m/Y' => gmdate( 'd/m/Y' ),
86 - 'custom' => esc_html__( 'Custom', 'uicore-elements' ),
87 - ],
88 - 'condition' => [
89 - 'type' => ['date','updated date']
90 - ]
84 + ]
85 + );
86 + $repeater->add_control(
87 + 'date_format',
88 + [
89 + 'label' => esc_html__('Date Format', 'uicore-elements'),
90 + 'type' => Controls_Manager::SELECT,
91 + 'default' => 'default',
92 + 'options' => [
93 + 'default' => esc_html__('Default', 'uicore-elements'),
94 + 'F j, Y' => gmdate('F j, Y'),
95 + 'Y-m-d' => gmdate('Y-m-d'),
96 + 'm/d/Y' => gmdate('m/d/Y'),
97 + 'd/m/Y' => gmdate('d/m/Y'),
98 + 'custom' => esc_html__('Custom', 'uicore-elements'),
99 + ],
100 + 'condition' => [
101 + 'type' => ['date', 'updated date']
91 102 ]
92 - );
93 - $repeater->add_control('custom_format',[
94 - 'label' => esc_html__( 'Custom Format', 'uicore-elements' ),
95 - 'default' => get_option( 'date_format' ) . ' ' . get_option( 'time_format' ),
96 - 'description' => sprintf( '<a href="https://wordpress.org/documentation/article/customize-date-and-time-format/" target="_blank">%s</a>', esc_html__( 'Documentation on date and time formatting', 'uicore-elements' ) ),
97 - 'condition' => [
98 - 'date_format' => 'custom',
99 - 'type' => ['date','updated date']
100 - ],
103 + ]
104 + );
105 + $repeater->add_control(
106 + 'custom_format',
107 + [
108 + 'label' => esc_html__('Custom Format', 'uicore-elements'),
109 + 'default' => get_option('date_format') . ' ' . get_option('time_format'),
110 + 'description' => sprintf('<a href="https://wordpress.org/documentation/article/customize-date-and-time-format/" target="_blank">%s</a>', esc_html__('Documentation on date and time formatting', 'uicore-elements')),
111 + 'condition' => [
112 + 'date_format' => 'custom',
113 + 'type' => ['date', 'updated date']
114 + ],
115 + ]
116 + );
117 + $repeater->add_control(
118 + 'stock_type',
119 + [
120 + 'label' => esc_html__('Stock Data', 'uicore-elements'),
121 + 'type' => Controls_Manager::SELECT,
122 + 'default' => 'qty',
123 + 'options' => [
124 + 'qty' => esc_html__('Quantity', 'uicore-elements'),
125 + 'in' => esc_html__('In/Out of stock', 'uicore-elements'),
126 + ],
127 + 'condition' => [
128 + 'type' => ['product stock']
101 129 ]
102 - );
103 - $repeater->add_control('before',[
104 - 'label' => __( 'Text Before', 'uicore-elements' ),
130 + ]
131 + );
132 + $repeater->add_control(
133 + 'in_stock_text',
134 + [
135 + 'label' => esc_html__('In Stock Text', 'uicore-elements'),
105 136 'type' => Controls_Manager::TEXT,
137 + 'default' => esc_html__('In Stock', 'uicore-elements'),
106 138 'condition' => [
139 + 'type' => ['product stock'],
140 + 'stock_type' => 'in',
141 + ]
142 + ]
143 + );
144 + $repeater->add_control(
145 + 'out_of_stock_text',
146 + [
147 + 'label' => esc_html__('Out of Stock Text', 'uicore-elements'),
148 + 'type' => Controls_Manager::TEXT,
149 + 'default' => esc_html__('Out of Stock', 'uicore-elements'),
150 + 'condition' => [
151 + 'type' => ['product stock'],
152 + ]
153 + ]
154 + );
155 + $repeater->add_control(
156 + 'in_stock_color',
157 + [
158 + 'label' => __('In Stock Color', 'uicore-elements'),
159 + 'type' => Controls_Manager::COLOR,
160 + 'selectors' => [
161 + '{{WRAPPER}} .in-stock' => 'color: {{VALUE}}',
162 + ],
163 + 'condition' => [
164 + 'type' => ['product stock'],
165 + ]
166 + ]
167 + );
168 + $repeater->add_control(
169 + 'out_of_stock_color',
170 + [
171 + 'label' => __('Out of Stock Color', 'uicore-elements'),
172 + 'type' => Controls_Manager::COLOR,
173 + 'selectors' => [
174 + '{{WRAPPER}} .out-of-stock' => 'color: {{VALUE}}',
175 + ],
176 + 'condition' => [
177 + 'type' => ['product stock'],
178 + ]
179 + ]
180 + );
181 + $repeater->add_control(
182 + 'before',
183 + [
184 + 'label' => __('Text Before', 'uicore-elements'),
185 + 'type' => Controls_Manager::TEXT,
186 + 'condition' => [
107 187 'type!' => 'none',
108 188 ]
109 189 ]
110 190 );
111 - $repeater->add_control('after',[
112 - 'label' => __( 'Text After', 'uicore-elements' ),
191 + $repeater->add_control(
192 + 'after',
193 + [
194 + 'label' => __('Text After', 'uicore-elements'),
113 195 'type' => Controls_Manager::TEXT,
114 196 'condition' => [
115 197 'type!' => 'none',
116 198 ]
@@ -115,16 +197,18 @@
115 197 'type!' => 'none',
116 198 ]
117 199 ]
118 200 );
119 - $repeater->add_control('autor_display',[
120 - 'label' => __( 'Display Type', 'uicore-elements' ),
201 + $repeater->add_control(
202 + 'autor_display',
203 + [
204 + 'label' => __('Display Type', 'uicore-elements'),
121 205 'type' => Controls_Manager::SELECT,
122 206 'default' => 'name',
123 207 'options' => [
124 - 'name' => __( 'Name', 'uicore-elements' ),
125 - 'full' => __( 'Avatar & Name', 'uicore-elements' ),
126 - 'avatar' => __( 'Avatar', 'uicore-elements' ),
208 + 'name' => __('Name', 'uicore-elements'),
209 + 'full' => __('Avatar & Name', 'uicore-elements'),
210 + 'avatar' => __('Avatar', 'uicore-elements'),
127 211 ],
128 212 'condition' => [
129 213 'type' => 'author',
130 214 ],
@@ -129,10 +213,12 @@
129 213 'type' => 'author',
130 214 ],
131 215 ]
132 216 );
133 - $repeater->add_control('icon',[
134 - 'label' => __( 'Icon', 'uicore-elements' ),
217 + $repeater->add_control(
218 + 'icon',
219 + [
220 + 'label' => __('Icon', 'uicore-elements'),
135 221 'type' => Controls_Manager::ICONS,
136 222 'condition' => [
137 223 'autor_display' => 'name',
138 224 'type!' => 'none',
@@ -144,127 +230,131 @@
144 230
145 231 function get_meta_style_controls($position = 'tb-meta')
146 232 {
147 233 $this->add_group_control(
148 - Group_Control_Typography::get_type(),
149 - [
150 - 'name' => $position.'_meta_typography',
151 - 'selector' => '{{WRAPPER}} .ui-e-'.$position,
234 + Group_Control_Typography::get_type(),
235 + [
236 + 'name' => $position . '_meta_typography',
237 + 'selector' => '{{WRAPPER}} .ui-e-' . $position,
152 238 'separator' => 'before',
153 - ]
154 - );
239 + ]
240 + );
155 241 $this->add_control(
156 - $position.'_meta_color',
157 - [
158 - 'label' => __( 'Text Color', 'uicore-elements' ),
159 - 'type' => Controls_Manager::COLOR,
160 - 'selectors' => [
161 - '{{WRAPPER}} .ui-e-'.$position => 'color: {{VALUE}}',
162 - '{{WRAPPER}} .ui-e-'.$position.' svg' => 'fill: {{VALUE}}',
163 - ],
164 - ]
165 - );
242 + $position . '_meta_color',
243 + [
244 + 'label' => __('Text Color', 'uicore-elements'),
245 + 'type' => Controls_Manager::COLOR,
246 + 'selectors' => [
247 + '{{WRAPPER}} .ui-e-' . $position => 'color: {{VALUE}}',
248 + '{{WRAPPER}} .ui-e-' . $position . ' svg' => 'fill: {{VALUE}}',
249 + ],
250 + ]
251 + );
166 252 $this->add_control(
167 - $position.'_link_color',
168 - [
169 - 'label' => __( 'Link Color', 'uicore-elements' ),
170 - 'type' => Controls_Manager::COLOR,
171 - 'selectors' => [
172 - '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item a' => 'color: {{VALUE}}',
173 - '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item svg' => 'fill: {{VALUE}}',
174 - ],
175 - ]
176 - );
253 + $position . '_link_color',
254 + [
255 + 'label' => __('Link Color', 'uicore-elements'),
256 + 'type' => Controls_Manager::COLOR,
257 + 'selectors' => [
258 + '{{WRAPPER}} .ui-e-' . $position . ' .ui-e-meta-item a' => 'color: {{VALUE}}',
259 + '{{WRAPPER}} .ui-e-' . $position . ' .ui-e-meta-item svg' => 'fill: {{VALUE}}',
260 + ],
261 + ]
262 + );
177 263 $this->add_control(
178 - $position.'_linkh_color',
179 - [
180 - 'label' => __( 'Link Hover Color', 'uicore-elements' ),
181 - 'type' => Controls_Manager::COLOR,
182 - 'selectors' => [
183 - '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item a:hover' => 'color: {{VALUE}}',
184 - ],
185 - ]
186 - );
264 + $position . '_linkh_color',
265 + [
266 + 'label' => __('Link Hover Color', 'uicore-elements'),
267 + 'type' => Controls_Manager::COLOR,
268 + 'selectors' => [
269 + '{{WRAPPER}} .ui-e-' . $position . ' .ui-e-meta-item a:hover' => 'color: {{VALUE}}',
270 + ],
271 + ]
272 + );
187 273 $this->add_control(
188 - $position.'_meta_background',
189 - [
190 - 'label' => __( 'Background Color', 'uicore-elements' ),
191 - 'type' => Controls_Manager::COLOR,
192 - 'selectors' => [
193 - '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item' => 'background-color: {{VALUE}}',
274 + $position . '_meta_background',
275 + [
276 + 'label' => __('Background Color', 'uicore-elements'),
277 + 'type' => Controls_Manager::COLOR,
278 + 'selectors' => [
279 + '{{WRAPPER}} .ui-e-' . $position . ' .ui-e-meta-item' => 'background-color: {{VALUE}}',
194 280
195 - ],
196 - ]
197 - );
281 + ],
282 + ]
283 + );
198 284 $this->add_control(
199 - $position.'_meta_radius',
200 - [
201 - 'label' => esc_html__('Border Radius', 'uicore-elements'),
202 - 'type' => Controls_Manager::DIMENSIONS,
203 - 'selectors' => [
204 - '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item' => 'border-radius: {{TOP}}px {{RIGHT}}px {{BOTTOM}}px {{LEFT}}px;'
205 - ],
206 - ]
207 - );
285 + $position . '_meta_radius',
286 + [
287 + 'label' => esc_html__('Border Radius', 'uicore-elements'),
288 + 'type' => Controls_Manager::DIMENSIONS,
289 + 'selectors' => [
290 + '{{WRAPPER}} .ui-e-' . $position . ' .ui-e-meta-item' => 'border-radius: {{TOP}}px {{RIGHT}}px {{BOTTOM}}px {{LEFT}}px;'
291 + ],
292 + ]
293 + );
208 294 $this->add_group_control(
209 - \Elementor\Group_Control_Box_Shadow::get_type(),
210 - [
211 - 'name' => $position.'_meta_shadow',
212 - 'label' => esc_html__( 'Box Shadow', 'uicore-elements' ),
213 - 'selector' => '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item',
214 - ]
215 - );
216 - $this->add_responsive_control(
217 - $position.'_meta_padding',
218 - [
219 - 'label' => esc_html__('Padding', 'uicore-elements'),
220 - 'type' => Controls_Manager::DIMENSIONS,
221 - 'size_units' => [ 'px', 'em', '%' ],
222 - 'selectors' => [
223 - '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
224 - ]
225 - ]
226 - );
227 - if($position === 'top'){
295 + \Elementor\Group_Control_Box_Shadow::get_type(),
296 + [
297 + 'name' => $position . '_meta_shadow',
298 + 'label' => esc_html__('Box Shadow', 'uicore-elements'),
299 + 'selector' => '{{WRAPPER}} .ui-e-' . $position . ' .ui-e-meta-item',
300 + ]
301 + );
302 + $this->add_responsive_control(
303 + $position . '_meta_padding',
304 + [
305 + 'label' => esc_html__('Padding', 'uicore-elements'),
306 + 'type' => Controls_Manager::DIMENSIONS,
307 + 'size_units' => ['px', 'em', '%'],
308 + 'selectors' => [
309 + '{{WRAPPER}} .ui-e-' . $position . ' .ui-e-meta-item' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
310 + ]
311 + ]
312 + );
313 + if ($position === 'top') {
228 314 $this->add_responsive_control(
229 - $position.'_meta_margin',
315 + $position . '_meta_margin',
230 316 [
231 317 'label' => esc_html__('Margin', 'uicore-elements'),
232 318 'type' => Controls_Manager::DIMENSIONS,
233 - 'size_units' => [ 'px', 'em', '%' ],
319 + 'size_units' => ['px', 'em', '%'],
234 320 'selectors' => [
235 - '{{WRAPPER}} .ui-e-'.$position => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
321 + '{{WRAPPER}} .ui-e-' . $position => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
236 322 ]
237 323 ]
238 324 );
239 - }else{
240 - $this->add_control($position.'_meta_margin',[
241 - 'label' => __( 'Meta Top Space', 'uicore-elements' ),
242 - 'type' => Controls_Manager::SLIDER,
243 - 'size_units' => [ 'em' ],
244 - 'separator' => 'after',
245 - 'range' => [
246 - 'px' => [
247 - 'min' => 0,
248 - 'max' => 3,
249 - 'step' => 0.1,
325 + } else {
326 + $this->add_control(
327 + $position . '_meta_margin',
328 + [
329 + 'label' => __('Meta Top Space', 'uicore-elements'),
330 + 'type' => Controls_Manager::SLIDER,
331 + 'size_units' => ['em'],
332 + 'separator' => 'after',
333 + 'range' => [
334 + 'px' => [
335 + 'min' => 0,
336 + 'max' => 3,
337 + 'step' => 0.1,
338 + ],
250 339 ],
251 - ],
252 - 'default' => [
253 - 'unit' => 'em',
254 - 'size' => 1.2,
255 - ],
256 - 'selectors' => [
257 - '{{WRAPPER}} .ui-e-'.$position => 'margin-top: {{SIZE}}em;',
258 - ],
259 - ]
260 - );
340 + 'default' => [
341 + 'unit' => 'em',
342 + 'size' => 1.2,
343 + ],
344 + 'selectors' => [
345 + '{{WRAPPER}} .ui-e-' . $position => 'margin-top: {{SIZE}}em;',
346 + ],
347 + ]
348 + );
261 349 }
262 350
263 - $this->add_responsive_control($position.'_meta_gap',[
264 - 'label' => __( 'Items Gap', 'uicore-elements' ),
351 + $this->add_responsive_control(
352 + $position . '_meta_gap',
353 + [
354 + 'label' => __('Items Gap', 'uicore-elements'),
265 355 'type' => Controls_Manager::SLIDER,
266 - 'size_units' => [ 'px' ],
356 + 'size_units' => ['px'],
267 357 'range' => [
268 358 'px' => [
269 359 'min' => 0,
270 360 'max' => 30,
@@ -274,59 +364,67 @@
274 364 'unit' => 'px',
275 365 'size' => 8,
276 366 ],
277 367 'selectors' => [
278 - '{{WRAPPER}} .ui-e-'.$position.' ' => 'gap: {{SIZE}}px;',
368 + '{{WRAPPER}} .ui-e-' . $position . ' ' => 'gap: {{SIZE}}px;',
279 369 ],
280 370 ]
281 371 );
282 - $this->add_control($position.'_meta_separator',[
283 - 'label' => __( 'Separator', 'uicore-elements' ),
372 + $this->add_control(
373 + $position . '_meta_separator',
374 + [
375 + 'label' => __('Separator', 'uicore-elements'),
284 376 'type' => Controls_Manager::TEXT,
285 377 ]
286 378 );
287 - if($position === 'top'){
288 - $this->add_control($position.'_meta_placement',[
289 - 'label' => __( 'Items placement', 'uicore-elements' ),
290 - 'type' => Controls_Manager::SELECT,
291 - 'default' => '',
292 - 'options' => [
293 - 'start left' => __( 'Top Left', 'uicore-elements' ),
294 - 'start right' => __( 'Top Right', 'uicore-elements' ),
295 - 'end left' => __( 'Bottom Left', 'uicore-elements' ),
296 - 'end right' => __( 'Bottom Right', 'uicore-elements' ),
297 - ],
298 - 'selectors' => [
299 - '{{WRAPPER}} .ui-e-post-top-meta' => 'place-content: {{VALUE}};',
300 - ],
379 + if ($position === 'top') {
380 + $this->add_control(
381 + $position . '_meta_placement',
382 + [
383 + 'label' => __('Items placement', 'uicore-elements'),
384 + 'type' => Controls_Manager::SELECT,
385 + 'default' => '',
386 + 'options' => [
387 + 'start left' => __('Top Left', 'uicore-elements'),
388 + 'start right' => __('Top Right', 'uicore-elements'),
389 + 'end left' => __('Bottom Left', 'uicore-elements'),
390 + 'end right' => __('Bottom Right', 'uicore-elements'),
391 + ],
392 + 'selectors' => [
393 + '{{WRAPPER}} .ui-e-post-top-meta' => 'place-content: {{VALUE}};',
394 + ],
301 395 ]
302 396 );
303 397 }
304 398 }
305 399
306 - function get_meta_the_author($mode){
400 + function get_meta_the_author($mode)
401 + {
307 402 global $post;
308 403 $author_id = $post->post_author;
404 + $author_name = get_the_author_meta('display_name', $author_id);
309 405
310 406 // name, full, avatar
311 - if($mode === 'avatar'){
312 - $display = '<img class="ui-e-meta-avatar" src="' . esc_url( get_avatar_url($author_id, array('size' => 100)) ) . '" />';
313 - }elseif($mode === 'full'){
314 - $display = '<img class="ui-e-meta-avatar" src="' . esc_url( get_avatar_url($author_id, array('size' => 100)) ) . '" /> '.get_the_author_meta('display_name', $author_id);
315 - }else{
316 - $display = esc_html(\get_the_author_meta('display_name', $author_id));
407 + if ($mode === 'avatar') {
408 + $display = '<img class="ui-e-meta-avatar" src="' . esc_url(get_avatar_url($author_id, array('size' => 100))) . '" />';
409 + } elseif ($mode === 'full') {
410 + $display = '<img class="ui-e-meta-avatar" src="' . esc_url(get_avatar_url($author_id, array('size' => 100))) . '" /> ' . esc_html($author_name);
411 + } else {
412 + $display = esc_html($author_name);
317 413 }
318 414 $link = sprintf(
415 + /* translators: 1: Author archive url, 2: Author meta title, 3: Author display name */
319 416 '<a href="%1$s" title="%2$s" rel="author">%3$s</a>',
320 - esc_url( get_author_posts_url( $author_id) ),
417 + esc_url(get_author_posts_url($author_id)),
321 418 /* translators: %s: Author's display name. */
322 - esc_attr( sprintf( __( 'View %s&#8217;s posts', 'uicore-elements' ), esc_html($display) ) ),
419 + esc_attr(sprintf(__('View %s&#8217;s posts', 'uicore-elements'), esc_html($author_name))),
323 420 $display
324 421 );
325 422 return $link;
326 423 }
327 424
328 - function get_woo_meta($type) {
425 + function get_woo_meta($type, $meta = null)
426 + {
329 427 global $product;
330 428
331 429 if (empty($product)) {
332 430 return 'No product found.';
@@ -335,38 +433,193 @@
335 433 switch ($type) {
336 434 case 'product price':
337 435 return $product->get_price_html();
338 436 case 'product rating':
339 - return wc_get_rating_html( $product->get_average_rating() );
437 + return wc_get_rating_html($product->get_average_rating());
340 438 case 'product category':
341 439 return get_the_term_list($product->get_id(), 'product_cat', '', ', ', '');
342 440 case 'product tag':
343 441 return get_the_term_list($product->get_id(), 'product_tag', '', ', ', '');
344 - case 'product stock' :
345 - return ( $product->managing_stock() && $product->is_type('simple') && $product->get_stock_quantity() !== null ) ? $product->get_stock_quantity() : '';
442 + case 'product stock':
443 + return $this->get_product_stock_for_widget_meta($product, $meta);
346 444 case 'product attribute':
347 - return wc_display_product_attributes($product);
348 - case 'product sale' :
349 - return $product->is_on_sale() ? esc_html__( 'Sale!', 'uicore-elements' ) : '';
445 + return $this->print_product_attributes($product);
446 + case 'product sale':
447 + return $product->is_on_sale() ? esc_html__('Sale!', 'uicore-elements') : '';
350 448 default:
351 449 return 'Invalid meta type.';
352 450 }
353 451 }
354 452
453 + /**
454 + * Get the product stock quantity for Advanced Product widget meta. If the product is variable, return the highest stock quantity among its variations.
455 + * TODO: this function should be part of the product TRAIT, but product trait uses this meta trait, so we'd have a circular dependency.
456 + *
457 + * @param WC_Product $product The WooCommerce product object.
458 + * @param array $meta The meta settings array.
459 + */
460 + function get_product_stock_for_widget_meta($product, $meta)
461 + {
355 462
356 - function display_meta($meta){
463 + // In/out of stock return
464 + if (isset($meta['stock_type']) && $meta['stock_type'] === 'in') {
357 465
358 - if($meta['type'] === 'none')
466 + $in_stock = false;
467 +
468 + if ($product->is_type('variable')) {
469 + foreach ($product->get_children() as $child_id) {
470 + $variation = wc_get_product($child_id);
471 + if ($variation && $variation->is_in_stock()) {
472 + $in_stock = true;
473 + break;
474 + }
475 + }
476 + } else {
477 + $in_stock = $product->is_in_stock();
478 + }
479 +
480 + return $in_stock
481 + ? '<span class="in-stock">' . esc_html($meta['in_stock_text'] ?? __('In stock', 'uicore-elements')) . '</span>'
482 + : '<span class="out-of-stock">' . esc_html($meta['out_of_stock_text'] ?? __('Out of stock', 'uicore-elements')) . '</span>';
483 + }
484 +
485 + // Quantity return
486 + if ($product->is_type('variable')) {
487 +
488 + $qty = 0;
489 +
490 + // Find the maximum stock quantity among variations
491 + foreach ($product->get_available_variations() as $variation) {
492 + $obj = wc_get_product($variation['variation_id']);
493 +
494 + if ($obj->managing_stock()) {
495 + $stock = $obj->get_stock_quantity();
496 + if ($stock > $qty) {
497 + $qty = $stock;
498 + }
499 + }
500 + }
501 +
502 + return $qty > 0
503 + ? '<span class="in-stock">' . esc_html($qty) . '</span>'
504 + : '<span class="out-of-stock">' . esc_html($meta['out_of_stock_text'] ?? __('Out of stock', 'uicore-elements')) . '</span>';
505 + }
506 +
507 + if (!$product->managing_stock()) {
508 + return '<span class="in-stock">' . esc_html($meta['in_stock_text'] ?? __('In stock', 'uicore-elements')) . '</span>';
509 + }
510 +
511 + return $product->get_stock_quantity() !== null
512 + ? $product->get_stock_quantity()
513 + : '';
514 + }
515 +
516 + /**
517 + * Gets and prints a list of product attributes. We use a custom function for it because
518 + * `wc_display_product_attributes` uses a table layout wich is not suitable for our widget.
519 + *
520 + * @param WC_Product $product The WooCommerce product object.
521 + * @return string|false The HTML string of product attributes or false if none are visible.
522 + * @since 1.3.13
523 + */
524 + function print_product_attributes($product)
525 + {
526 +
527 + $attributes = $product->get_attributes();
528 +
529 + if (empty($attributes)) {
530 + return false;
531 + }
532 +
533 + $default = true; // Flag to check if we're actually displaying any attribute
534 + $content = '<ul class="ui-e-product-attributes">';
535 +
536 + foreach ($attributes as $attribute) {
537 + if (! $attribute->get_visible()) {
538 + continue;
539 + }
540 +
541 + // We only want to display default attributes here that are not using framework swatches
542 + $swatch = $this->get_swatch_type($attribute->get_name());
543 + if ($swatch && in_array($swatch, ['color', 'label', 'button', 'image'])) {
544 + continue;
545 + }
546 +
547 + $default = false; // Safe to output html
548 + $name = wc_attribute_label($attribute->get_name());
549 + $value = '';
550 +
551 + if ($attribute->is_taxonomy()) {
552 + $taxonomy = $attribute->get_name();
553 + $terms = wc_get_product_terms(
554 + $product->get_id(),
555 + $taxonomy,
556 + ['fields' => 'all']
557 + );
558 +
559 + $term_links = [];
560 + $taxonomy_obj = get_taxonomy($taxonomy);
561 + $has_archive = $taxonomy_obj && $taxonomy_obj->public && $taxonomy_obj->rewrite && !empty($taxonomy_obj->rewrite['slug']);
562 +
563 + foreach ($terms as $term) {
564 + if ($has_archive && get_term_link($term)) {
565 + $term_links[] = '<a href="' . esc_url(get_term_link($term)) . '">' . esc_html($term->name) . '</a>';
566 + } else {
567 + $term_links[] = esc_html($term->name);
568 + }
569 + }
570 + $value = implode(', ', $term_links);
571 + } else {
572 + $value = implode(', ', $attribute->get_options());
573 + }
574 +
575 + if (empty($value)) {
576 + continue;
577 + }
578 +
579 + $content .= '<li>';
580 + $content .= '<strong>' . esc_html($name) . ':</strong> ';
581 + $content .= $value;
582 + $content .= '</li>';
583 + }
584 +
585 + if ($default) {
586 + return false;
587 + }
588 +
589 + $content .= '</ul>';
590 + return $content;
591 + }
592 +
593 + /**
594 + * Get the attribute swatch type from Uicore Framework plugin.
595 + *
596 + * @return string The swatch type.
597 + * @since 1.3.15
598 + */
599 + function get_swatch_type($attribute_slug)
600 + {
601 + if (!class_exists('Uicore\WooCommerce\Swatches') && !function_exists('get_attribute_swatch_type')) {
602 + return false;
603 + }
604 +
605 + return \Uicore\WooCommerce\Swatches::get_attribute_swatch_type($attribute_slug);
606 + }
607 +
608 + function display_meta($meta, $product_id = null)
609 + {
610 +
611 + if ($meta['type'] === 'none')
359 612 return;
360 613
361 614 $content = '';
362 615 $wrapper = '<div class="ui-e-meta-item">';
363 616 $type = $meta['type'];
364 - $prefix = $meta['before'] ? '<span>'.esc_html($meta['before']).'</span>' : '';
365 - $suffix = $meta['after'] ? '<span class="ui-e-meta-after">'.esc_html($meta['after']).'</span>' : '';
617 + $prefix = $meta['before'] ? '<span>' . esc_html($meta['before']) . '</span>' : '';
618 + $suffix = $meta['after'] ? '<span class="ui-e-meta-after">' . esc_html($meta['after']) . '</span>' : '';
366 619
367 620 ob_start();
368 - \Elementor\Icons_Manager::render_icon( $meta['icon'], [ 'aria-hidden' => 'true', 'class'=> 'ui-e-meta-icon' ], 'span' );
621 + \Elementor\Icons_Manager::render_icon($meta['icon'], ['aria-hidden' => 'true', 'class' => 'ui-e-meta-icon'], 'span');
369 622 $icon = ob_get_clean();
370 623
371 624 // Build content
372 625 switch ($type) {
@@ -381,8 +634,11 @@
381 634 break;
382 635 case 'category':
383 636 $content .= Helper::get_taxonomy('category');
384 637 break;
638 + case 'tag':
639 + $content .= Helper::get_taxonomy('post_tag');
640 + break;
385 641 case 'portfolio category':
386 642 $content .= Helper::get_taxonomy('portfolio_category');
387 643 break;
388 644 case 'comment':
@@ -388,9 +644,9 @@
388 644 case 'comment':
389 645 $content .= esc_html(get_comments_number());
390 646 break;
391 647 case 'custom meta':
392 - $content .= esc_html(get_post_meta( get_the_ID(), $meta['type_custom'], true ));
648 + $content .= Helper::get_custom_meta($meta['type_custom'], $product_id);
393 649 break;
394 650 case 'custom taxonomy':
395 651 $content .= Helper::get_taxonomy($meta['type_custom']);
396 652 break;
@@ -399,12 +655,16 @@
399 655 break;
400 656 case 'reading time':
401 657 $content .= esc_html(Helper::get_reading_time());
402 658 break;
659 + case 'excerpt':
660 + $content .= esc_html(get_the_excerpt());
661 + break;
403 662 default:
404 663 if (strpos($type, 'product') === 0) {
405 - if ($this->get_woo_meta($type) === false) return; // Abort if there's no data for this product meta
406 - $content .= wp_kses_post($this->get_woo_meta($type));
664 + $data = $this->get_woo_meta($type, $meta);
665 + if ($data === false) return;
666 + $content .= wp_kses_post($data);
407 667 } else {
408 668 echo \esc_html($type);
409 669 }
410 670 break;
@@ -414,5 +674,5 @@
414 674 if (!empty($content)) {
415 675 echo $wrapper . Helper::esc_svg($icon) . $prefix . $content . $suffix . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
416 676 }
417 677 }
418 -}
678 +}