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