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 +471 -218 1.2.01.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,35 +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' ),
28 - 'tag' => __( 'Tag', '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'),
29 32 ];
30 33 $products = [
31 - 'product price' => __( 'Product Price', 'uicore-elements' ),
32 - 'product rating' => __( 'Product Rating', 'uicore-elements' ),
33 - 'product stock' => __( 'Product Stock', 'uicore-elements' ),
34 - 'product category' => __( 'Product Category', 'uicore-elements' ),
35 - 'product tag' => __( 'Product Tag', 'uicore-elements' ),
36 - 'product attribute' => __( 'Product Attribute', 'uicore-elements' ),
37 - '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'),
38 41 ];
39 42 $custom = [
40 - 'custom meta' => __( 'Custom Meta', 'uicore-elements' ),
41 - 'custom taxonomy' => __( 'Custom Taxonomy', 'uicore-elements' ),
42 - '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'),
43 46 ];
44 47 $portfolio = [
45 - 'portfolio category' => __( 'Portfolio Category', 'uicore-elements' ),
48 + 'portfolio category' => __('Portfolio Category', 'uicore-elements'),
46 49 ];
47 50
48 51 $options = $product_metas ?
49 52 array_merge($options, $products, $custom) : // specific to product widgets
@@ -50,68 +53,146 @@
50 53 array_merge($options, $generic_posts, $products, $portfolio, $custom); // generic posts widgets
51 54
52 55
53 56 $repeater = new \Elementor\Repeater();
54 - $repeater->add_control('type',[
55 - 'label' => __( 'Meta', 'uicore-elements' ),
57 + $repeater->add_control(
58 + 'type',
59 + [
60 + 'label' => __('Meta', 'uicore-elements'),
56 61 'type' => Controls_Manager::SELECT,
57 62 'default' => '',
58 63 'options' => $options
59 64 ]
60 65 );
61 - $repeater->add_control('type_custom',[
62 - 'label' => __( 'Custom Field Name', 'uicore-elements' ),
63 - 'type' => Controls_Manager::TEXT,
64 - 'condition' => [
65 - 'type' => ['custom meta','custom taxonomy']
66 - ]
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']
67 73 ]
68 - );
69 - $repeater->add_control('html_custom',[
70 - 'label' => __( 'Custom HTML', 'uicore-elements' ),
71 - 'type' => Controls_Manager::TEXTAREA,
72 - 'condition' => [
73 - 'type' => ['custom html']
74 - ]
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']
75 83 ]
76 - );
77 - $repeater->add_control('date_format',[
78 - 'label' => esc_html__( 'Date Format', 'uicore-elements' ),
79 - 'type' => Controls_Manager::SELECT,
80 - 'default' => 'default',
81 - 'options' => [
82 - 'default' => esc_html__( 'Default', 'uicore-elements' ),
83 - 'F j, Y' => gmdate( 'F j, Y' ),
84 - 'Y-m-d' => gmdate( 'Y-m-d' ),
85 - 'm/d/Y' => gmdate( 'm/d/Y' ),
86 - 'd/m/Y' => gmdate( 'd/m/Y' ),
87 - 'custom' => esc_html__( 'Custom', 'uicore-elements' ),
88 - ],
89 - 'condition' => [
90 - 'type' => ['date','updated date']
91 - ]
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']
92 102 ]
93 - );
94 - $repeater->add_control('custom_format',[
95 - 'label' => esc_html__( 'Custom Format', 'uicore-elements' ),
96 - 'default' => get_option( 'date_format' ) . ' ' . get_option( 'time_format' ),
97 - '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' ) ),
98 - 'condition' => [
99 - 'date_format' => 'custom',
100 - 'type' => ['date','updated date']
101 - ],
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']
102 129 ]
103 - );
104 - $repeater->add_control('before',[
105 - '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'),
106 136 'type' => Controls_Manager::TEXT,
137 + 'default' => esc_html__('In Stock', 'uicore-elements'),
107 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' => [
108 187 'type!' => 'none',
109 188 ]
110 189 ]
111 190 );
112 - $repeater->add_control('after',[
113 - 'label' => __( 'Text After', 'uicore-elements' ),
191 + $repeater->add_control(
192 + 'after',
193 + [
194 + 'label' => __('Text After', 'uicore-elements'),
114 195 'type' => Controls_Manager::TEXT,
115 196 'condition' => [
116 197 'type!' => 'none',
117 198 ]
@@ -116,16 +197,18 @@
116 197 'type!' => 'none',
117 198 ]
118 199 ]
119 200 );
120 - $repeater->add_control('autor_display',[
121 - 'label' => __( 'Display Type', 'uicore-elements' ),
201 + $repeater->add_control(
202 + 'autor_display',
203 + [
204 + 'label' => __('Display Type', 'uicore-elements'),
122 205 'type' => Controls_Manager::SELECT,
123 206 'default' => 'name',
124 207 'options' => [
125 - 'name' => __( 'Name', 'uicore-elements' ),
126 - 'full' => __( 'Avatar & Name', 'uicore-elements' ),
127 - 'avatar' => __( 'Avatar', 'uicore-elements' ),
208 + 'name' => __('Name', 'uicore-elements'),
209 + 'full' => __('Avatar & Name', 'uicore-elements'),
210 + 'avatar' => __('Avatar', 'uicore-elements'),
128 211 ],
129 212 'condition' => [
130 213 'type' => 'author',
131 214 ],
@@ -130,10 +213,12 @@
130 213 'type' => 'author',
131 214 ],
132 215 ]
133 216 );
134 - $repeater->add_control('icon',[
135 - 'label' => __( 'Icon', 'uicore-elements' ),
217 + $repeater->add_control(
218 + 'icon',
219 + [
220 + 'label' => __('Icon', 'uicore-elements'),
136 221 'type' => Controls_Manager::ICONS,
137 222 'condition' => [
138 223 'autor_display' => 'name',
139 224 'type!' => 'none',
@@ -145,127 +230,131 @@
145 230
146 231 function get_meta_style_controls($position = 'tb-meta')
147 232 {
148 233 $this->add_group_control(
149 - Group_Control_Typography::get_type(),
150 - [
151 - 'name' => $position.'_meta_typography',
152 - 'selector' => '{{WRAPPER}} .ui-e-'.$position,
234 + Group_Control_Typography::get_type(),
235 + [
236 + 'name' => $position . '_meta_typography',
237 + 'selector' => '{{WRAPPER}} .ui-e-' . $position,
153 238 'separator' => 'before',
154 - ]
155 - );
239 + ]
240 + );
156 241 $this->add_control(
157 - $position.'_meta_color',
158 - [
159 - 'label' => __( 'Text Color', 'uicore-elements' ),
160 - 'type' => Controls_Manager::COLOR,
161 - 'selectors' => [
162 - '{{WRAPPER}} .ui-e-'.$position => 'color: {{VALUE}}',
163 - '{{WRAPPER}} .ui-e-'.$position.' svg' => 'fill: {{VALUE}}',
164 - ],
165 - ]
166 - );
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 + );
167 252 $this->add_control(
168 - $position.'_link_color',
169 - [
170 - 'label' => __( 'Link Color', 'uicore-elements' ),
171 - 'type' => Controls_Manager::COLOR,
172 - 'selectors' => [
173 - '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item a' => 'color: {{VALUE}}',
174 - '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item svg' => 'fill: {{VALUE}}',
175 - ],
176 - ]
177 - );
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 + );
178 263 $this->add_control(
179 - $position.'_linkh_color',
180 - [
181 - 'label' => __( 'Link Hover Color', 'uicore-elements' ),
182 - 'type' => Controls_Manager::COLOR,
183 - 'selectors' => [
184 - '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item a:hover' => 'color: {{VALUE}}',
185 - ],
186 - ]
187 - );
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 + );
188 273 $this->add_control(
189 - $position.'_meta_background',
190 - [
191 - 'label' => __( 'Background Color', 'uicore-elements' ),
192 - 'type' => Controls_Manager::COLOR,
193 - 'selectors' => [
194 - '{{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}}',
195 280
196 - ],
197 - ]
198 - );
281 + ],
282 + ]
283 + );
199 284 $this->add_control(
200 - $position.'_meta_radius',
201 - [
202 - 'label' => esc_html__('Border Radius', 'uicore-elements'),
203 - 'type' => Controls_Manager::DIMENSIONS,
204 - 'selectors' => [
205 - '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item' => 'border-radius: {{TOP}}px {{RIGHT}}px {{BOTTOM}}px {{LEFT}}px;'
206 - ],
207 - ]
208 - );
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 + );
209 294 $this->add_group_control(
210 - \Elementor\Group_Control_Box_Shadow::get_type(),
211 - [
212 - 'name' => $position.'_meta_shadow',
213 - 'label' => esc_html__( 'Box Shadow', 'uicore-elements' ),
214 - 'selector' => '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item',
215 - ]
216 - );
217 - $this->add_responsive_control(
218 - $position.'_meta_padding',
219 - [
220 - 'label' => esc_html__('Padding', 'uicore-elements'),
221 - 'type' => Controls_Manager::DIMENSIONS,
222 - 'size_units' => [ 'px', 'em', '%' ],
223 - 'selectors' => [
224 - '{{WRAPPER}} .ui-e-'.$position.' .ui-e-meta-item' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
225 - ]
226 - ]
227 - );
228 - 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') {
229 314 $this->add_responsive_control(
230 - $position.'_meta_margin',
315 + $position . '_meta_margin',
231 316 [
232 317 'label' => esc_html__('Margin', 'uicore-elements'),
233 318 'type' => Controls_Manager::DIMENSIONS,
234 - 'size_units' => [ 'px', 'em', '%' ],
319 + 'size_units' => ['px', 'em', '%'],
235 320 'selectors' => [
236 - '{{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}};'
237 322 ]
238 323 ]
239 324 );
240 - }else{
241 - $this->add_control($position.'_meta_margin',[
242 - 'label' => __( 'Meta Top Space', 'uicore-elements' ),
243 - 'type' => Controls_Manager::SLIDER,
244 - 'size_units' => [ 'em' ],
245 - 'separator' => 'after',
246 - 'range' => [
247 - 'px' => [
248 - 'min' => 0,
249 - 'max' => 3,
250 - '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 + ],
251 339 ],
252 - ],
253 - 'default' => [
254 - 'unit' => 'em',
255 - 'size' => 1.2,
256 - ],
257 - 'selectors' => [
258 - '{{WRAPPER}} .ui-e-'.$position => 'margin-top: {{SIZE}}em;',
259 - ],
260 - ]
261 - );
340 + 'default' => [
341 + 'unit' => 'em',
342 + 'size' => 1.2,
343 + ],
344 + 'selectors' => [
345 + '{{WRAPPER}} .ui-e-' . $position => 'margin-top: {{SIZE}}em;',
346 + ],
347 + ]
348 + );
262 349 }
263 350
264 - $this->add_responsive_control($position.'_meta_gap',[
265 - 'label' => __( 'Items Gap', 'uicore-elements' ),
351 + $this->add_responsive_control(
352 + $position . '_meta_gap',
353 + [
354 + 'label' => __('Items Gap', 'uicore-elements'),
266 355 'type' => Controls_Manager::SLIDER,
267 - 'size_units' => [ 'px' ],
356 + 'size_units' => ['px'],
268 357 'range' => [
269 358 'px' => [
270 359 'min' => 0,
271 360 'max' => 30,
@@ -275,31 +364,35 @@
275 364 'unit' => 'px',
276 365 'size' => 8,
277 366 ],
278 367 'selectors' => [
279 - '{{WRAPPER}} .ui-e-'.$position.' ' => 'gap: {{SIZE}}px;',
368 + '{{WRAPPER}} .ui-e-' . $position . ' ' => 'gap: {{SIZE}}px;',
280 369 ],
281 370 ]
282 371 );
283 - $this->add_control($position.'_meta_separator',[
284 - 'label' => __( 'Separator', 'uicore-elements' ),
372 + $this->add_control(
373 + $position . '_meta_separator',
374 + [
375 + 'label' => __('Separator', 'uicore-elements'),
285 376 'type' => Controls_Manager::TEXT,
286 377 ]
287 378 );
288 - if($position === 'top'){
289 - $this->add_control($position.'_meta_placement',[
290 - 'label' => __( 'Items placement', 'uicore-elements' ),
291 - 'type' => Controls_Manager::SELECT,
292 - 'default' => '',
293 - 'options' => [
294 - 'start left' => __( 'Top Left', 'uicore-elements' ),
295 - 'start right' => __( 'Top Right', 'uicore-elements' ),
296 - 'end left' => __( 'Bottom Left', 'uicore-elements' ),
297 - 'end right' => __( 'Bottom Right', 'uicore-elements' ),
298 - ],
299 - 'selectors' => [
300 - '{{WRAPPER}} .ui-e-post-top-meta' => 'place-content: {{VALUE}};',
301 - ],
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 + ],
302 395 ]
303 396 );
304 397 }
305 398 }
@@ -307,29 +400,30 @@
307 400 function get_meta_the_author($mode)
308 401 {
309 402 global $post;
310 403 $author_id = $post->post_author;
404 + $author_name = get_the_author_meta('display_name', $author_id);
311 405
312 406 // name, full, avatar
313 - if($mode === 'avatar'){
314 - $display = '<img class="ui-e-meta-avatar" src="' . esc_url( get_avatar_url($author_id, array('size' => 100)) ) . '" />';
315 - }elseif($mode === 'full'){
316 - $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);
317 - }else{
318 - $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);
319 413 }
320 414 $link = sprintf(
321 415 /* translators: 1: Author archive url, 2: Author meta title, 3: Author display name */
322 416 '<a href="%1$s" title="%2$s" rel="author">%3$s</a>',
323 - esc_url( get_author_posts_url( $author_id) ),
417 + esc_url(get_author_posts_url($author_id)),
324 418 /* translators: %s: Author's display name. */
325 - 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))),
326 420 $display
327 421 );
328 422 return $link;
329 423 }
330 424
331 - function get_woo_meta($type)
425 + function get_woo_meta($type, $meta = null)
332 426 {
333 427 global $product;
334 428
335 429 if (empty($product)) {
@@ -339,38 +433,193 @@
339 433 switch ($type) {
340 434 case 'product price':
341 435 return $product->get_price_html();
342 436 case 'product rating':
343 - return wc_get_rating_html( $product->get_average_rating() );
437 + return wc_get_rating_html($product->get_average_rating());
344 438 case 'product category':
345 439 return get_the_term_list($product->get_id(), 'product_cat', '', ', ', '');
346 440 case 'product tag':
347 441 return get_the_term_list($product->get_id(), 'product_tag', '', ', ', '');
348 - case 'product stock' :
349 - 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);
350 444 case 'product attribute':
351 - return wc_display_product_attributes($product);
352 - case 'product sale' :
353 - 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') : '';
354 448 default:
355 449 return 'Invalid meta type.';
356 450 }
357 451 }
358 452
359 - function display_meta($meta)
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)
360 461 {
361 462
362 - if( $meta['type'] === 'none' )
463 + // In/out of stock return
464 + if (isset($meta['stock_type']) && $meta['stock_type'] === 'in') {
465 +
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')
363 612 return;
364 613
365 614 $content = '';
366 615 $wrapper = '<div class="ui-e-meta-item">';
367 616 $type = $meta['type'];
368 - $prefix = $meta['before'] ? '<span>'.esc_html($meta['before']).'</span>' : '';
369 - $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>' : '';
370 619
371 620 ob_start();
372 - \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');
373 622 $icon = ob_get_clean();
374 623
375 624 // Build content
376 625 switch ($type) {
@@ -377,12 +626,12 @@
377 626 case 'author':
378 627 $content .= $this->get_meta_the_author($meta['autor_display']); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
379 628 break;
380 629 case 'date':
381 - $content .= Helper::format_date( get_the_date('U'), $meta['date_format'], $meta['custom_format']); // 'U' param returns the date in timestamp, necessary for format_date()
630 + $content .= Helper::format_date(get_the_date('U'), $meta['date_format'], $meta['custom_format']); // 'U' param returns the date in timestamp, necessary for format_date()
382 631 break;
383 632 case 'updated date':
384 - $content .= Helper::format_date( get_the_modified_date('U'), $meta['date_format'], $meta['custom_format']); // 'U' param returns the date in timestamp, necessary for format_date()
633 + $content .= Helper::format_date(get_the_modified_date('U'), $meta['date_format'], $meta['custom_format']); // 'U' param returns the date in timestamp, necessary for format_date()
385 634 break;
386 635 case 'category':
387 636 $content .= Helper::get_taxonomy('category');
388 637 break;
@@ -392,12 +641,12 @@
392 641 case 'portfolio category':
393 642 $content .= Helper::get_taxonomy('portfolio_category');
394 643 break;
395 644 case 'comment':
396 - $content .= esc_html( get_comments_number() );
645 + $content .= esc_html(get_comments_number());
397 646 break;
398 647 case 'custom meta':
399 - $content .= Helper::get_custom_meta($meta['type_custom']);
648 + $content .= Helper::get_custom_meta($meta['type_custom'], $product_id);
400 649 break;
401 650 case 'custom taxonomy':
402 651 $content .= Helper::get_taxonomy($meta['type_custom']);
403 652 break;
@@ -404,14 +653,18 @@
404 653 case 'custom html':
405 654 $content .= wp_kses_post($meta['html_custom']);
406 655 break;
407 656 case 'reading time':
408 - $content .= esc_html( Helper::get_reading_time() );
657 + $content .= esc_html(Helper::get_reading_time());
409 658 break;
659 + case 'excerpt':
660 + $content .= esc_html(get_the_excerpt());
661 + break;
410 662 default:
411 663 if (strpos($type, 'product') === 0) {
412 - if ($this->get_woo_meta($type) === false) return; // Abort if there's no data for this product meta
413 - $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);
414 667 } else {
415 668 echo \esc_html($type);
416 669 }
417 670 break;
@@ -421,5 +674,5 @@
421 674 if (!empty($content)) {
422 675 echo $wrapper . Helper::esc_svg($icon) . $prefix . $content . $suffix . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
423 676 }
424 677 }
425 -}
678 +}