PluginProbe
MarqueeX – Smooth Marquee Slider, News Ticker & Post Marquee for Block Editor & Elementor / 0.6.0
MarqueeX – Smooth Marquee Slider, News Ticker & Post Marquee for Block Editor & Elementor v0.6.0
0.6.0 0.5.4 0.5.3 0.5.2 0.5.1 0.5.0 0.4.0 0.3.3 0.3.2 trunk 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.1.0 0.1.1 0.1.2 0.2.0 0.2.1 0.2.2 0.2.3 0.3.0 0.3.1
marqueex / includes / Integrations / Elementor / Widgets / TeamMembersMarquee.php

TeamMembersMarquee.php in MarqueeX – Smooth Marquee Slider, News Ticker & Post Marquee for Block Editor & Elementor 0.6.0, at includes/Integrations/Elementor/Widgets/TeamMembersMarquee.php

581 lines 18.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Wpxero\Marqueex\Integrations\Elementor\Widgets;
4
5 use Elementor\Widget_Base;
6 use Elementor\Controls_Manager;
7 use Elementor\Repeater;
8 use Elementor\Group_Control_Typography;
9 use Elementor\Group_Control_Border;
10 use Elementor\Group_Control_Box_Shadow;
11 use Elementor\Group_Control_Image_Size;
12
13 if (!defined('ABSPATH')) {
14 exit;
15 }
16
17 class TeamMembersMarquee extends Widget_Base {
18
19 public function get_name() {
20 return 'marqueex-team-members-marquee';
21 }
22
23 public function get_title() {
24 return __('Team Members Marquee', 'marqueex');
25 }
26
27 public function get_icon() {
28 return 'eicon-person eicon-marqueex';
29 }
30
31 public function get_categories() {
32 return ['marqueex'];
33 }
34
35 public function get_style_depends() {
36 return ['marqueex-team-members-marquee'];
37 }
38
39 public function get_script_depends() {
40 return ['marqueex-team-members-marquee'];
41 }
42
43 public function get_keywords() {
44 return ['team', 'members', 'marquee', 'staff', 'people', 'slider'];
45 }
46
47 protected function register_controls() {
48 $this->start_controls_section(
49 'content_section',
50 [
51 'label' => __('Team Members', 'marqueex'),
52 'tab' => Controls_Manager::TAB_CONTENT,
53 ]
54 );
55
56 $repeater = new Repeater();
57
58 $repeater->add_control(
59 'member_image',
60 [
61 'label' => __('Choose Image', 'marqueex'),
62 'type' => Controls_Manager::MEDIA,
63 'default' => [
64 'url' => \Elementor\Utils::get_placeholder_image_src(),
65 ],
66 ]
67 );
68
69 $repeater->add_control(
70 'member_name',
71 [
72 'label' => __('Name', 'marqueex'),
73 'type' => Controls_Manager::TEXT,
74 'default' => __('John Doe', 'marqueex'),
75 'label_block' => true,
76 ]
77 );
78
79 $repeater->add_control(
80 'member_role',
81 [
82 'label' => __('Job Role', 'marqueex'),
83 'type' => Controls_Manager::TEXT,
84 'default' => __('Team Member', 'marqueex'),
85 'label_block' => true,
86 ]
87 );
88
89 $this->add_control(
90 'team_members',
91 [
92 'label' => __('Team Members', 'marqueex'),
93 'type' => Controls_Manager::REPEATER,
94 'fields' => $repeater->get_controls(),
95 'default' => [
96 [
97 'member_name' => __('John Doe', 'marqueex'),
98 'member_role' => __('CEO & Founder', 'marqueex'),
99 ],
100 [
101 'member_name' => __('Jane Smith', 'marqueex'),
102 'member_role' => __('Lead Developer', 'marqueex'),
103 ],
104 [
105 'member_name' => __('Mike Johnson', 'marqueex'),
106 'member_role' => __('Designer', 'marqueex'),
107 ],
108 ],
109 'title_field' => '{{{ member_name }}}',
110 ]
111 );
112
113 $this->add_group_control(
114 Group_Control_Image_Size::get_type(),
115 [
116 'name' => 'thumbnail',
117 'default' => 'medium_large',
118 'separator' => 'before',
119 ]
120 );
121
122 $this->end_controls_section();
123
124 $this->start_controls_section(
125 'marquee_settings',
126 ['label' => __('Marquee Settings', 'marqueex')]
127 );
128
129 $this->add_control(
130 'orientation',
131 [
132 'label' => __('Orientation', 'marqueex'),
133 'type' => Controls_Manager::SELECT,
134 'default' => 'horizontal',
135 'options' => [
136 'horizontal' => __('Horizontal', 'marqueex'),
137 'vertical' => __('Vertical', 'marqueex'),
138 ],
139 ]
140 );
141
142 $this->add_control(
143 'vertical_height',
144 [
145 'label' => __('Height', 'marqueex'),
146 'type' => Controls_Manager::SLIDER,
147 'size_units' => ['vh', 'px'],
148 'range' => [
149 'vh' => ['min' => 20, 'max' => 100],
150 'px' => ['min' => 200, 'max' => 1000],
151 ],
152 'default' => ['size' => 60, 'unit' => 'vh'],
153 'condition' => ['orientation' => 'vertical'],
154 'selectors' => [
155 '{{WRAPPER}} .marqueex-marquee-block' => 'height: {{SIZE}}{{UNIT}};',
156 ],
157 ]
158 );
159
160 $this->add_control(
161 'reverse',
162 [
163 'label' => __('Reverse Direction', 'marqueex'),
164 'type' => Controls_Manager::SWITCHER,
165 'return_value' => 'yes',
166 ]
167 );
168
169 $this->add_control(
170 'pause',
171 [
172 'label' => __('Pause on Hover', 'marqueex'),
173 'type' => Controls_Manager::SWITCHER,
174 'return_value' => 'yes',
175 'default' => 'yes',
176 ]
177 );
178
179 $this->add_control(
180 'speed',
181 [
182 'label' => __('Speed (px/s)', 'marqueex'),
183 'type' => Controls_Manager::SLIDER,
184 'range' => ['px' => ['min' => 10, 'max' => 400]],
185 'default' => ['size' => 20, 'unit' => 'px'],
186 ]
187 );
188
189 $this->add_control(
190 'gap',
191 [
192 'label' => __('Gap (px)', 'marqueex'),
193 'type' => Controls_Manager::NUMBER,
194 'default' => 24,
195 'min' => 0,
196 'max' => 100,
197 ]
198 );
199
200 $this->add_control(
201 'mask_edges',
202 [
203 'label' => __('Soft Edge Mask', 'marqueex'),
204 'type' => Controls_Manager::SWITCHER,
205 'return_value' => 'yes',
206 ]
207 );
208
209 $this->add_control(
210 'image_effect',
211 [
212 'label' => __('Image Effect', 'marqueex'),
213 'type' => Controls_Manager::SELECT,
214 'default' => 'none',
215 'options' => [
216 'none' => __('None', 'marqueex'),
217 'grayscale' => __('Grayscale', 'marqueex'),
218 ],
219 'separator' => 'before',
220 ]
221 );
222
223 $this->end_controls_section();
224
225 $this->start_controls_section(
226 'style_section',
227 [
228 'label' => __('Team Member Box', 'marqueex'),
229 'tab' => Controls_Manager::TAB_STYLE,
230 ]
231 );
232
233 $this->add_control(
234 'box_background',
235 [
236 'label' => __('Background Color', 'marqueex'),
237 'type' => Controls_Manager::COLOR,
238 'selectors' => [
239 '{{WRAPPER}} .marqueex-team-member' => 'background-color: {{VALUE}};',
240 ],
241 ]
242 );
243
244 $this->add_group_control(
245 Group_Control_Border::get_type(),
246 [
247 'name' => 'box_border',
248 'selector' => '{{WRAPPER}} .marqueex-team-member',
249 ]
250 );
251
252 $this->add_responsive_control(
253 'box_border_radius',
254 [
255 'label' => __('Border Radius', 'marqueex'),
256 'type' => Controls_Manager::DIMENSIONS,
257 'selectors' => [
258 '{{WRAPPER}} .marqueex-team-member' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
259 ],
260 ]
261 );
262
263 $this->add_group_control(
264 Group_Control_Box_Shadow::get_type(),
265 [
266 'name' => 'box_shadow',
267 'selector' => '{{WRAPPER}} .marqueex-team-member',
268 ]
269 );
270
271 $this->add_responsive_control(
272 'box_padding',
273 [
274 'label' => __('Padding', 'marqueex'),
275 'type' => Controls_Manager::DIMENSIONS,
276 'size_units' => ['px', 'em', '%'],
277 'selectors' => [
278 '{{WRAPPER}} .marqueex-team-member' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
279 ],
280 ]
281 );
282
283 $this->add_control(
284 'content_alignment',
285 [
286 'label' => __('Content Alignment', 'marqueex'),
287 'type' => Controls_Manager::CHOOSE,
288 'options' => [
289 'left' => [
290 'title' => __('Left', 'marqueex'),
291 'icon' => 'eicon-text-align-left',
292 ],
293 'center' => [
294 'title' => __('Center', 'marqueex'),
295 'icon' => 'eicon-text-align-center',
296 ],
297 'right' => [
298 'title' => __('Right', 'marqueex'),
299 'icon' => 'eicon-text-align-right',
300 ],
301 ],
302 'default' => 'center',
303 'selectors' => [
304 '{{WRAPPER}} .marqueex-team-member-content' => 'text-align: {{VALUE}};',
305 ],
306 ]
307 );
308
309 $this->end_controls_section();
310
311 $this->start_controls_section(
312 'image_style_section',
313 [
314 'label' => __('Image', 'marqueex'),
315 'tab' => Controls_Manager::TAB_STYLE,
316 ]
317 );
318
319 $this->add_responsive_control(
320 'image_width',
321 [
322 'label' => __('Width', 'marqueex'),
323 'type' => Controls_Manager::SLIDER,
324 'size_units' => ['px', '%'],
325 'range' => [
326 'px' => ['min' => 50, 'max' => 500],
327 '%' => ['min' => 10, 'max' => 100],
328 ],
329 'default' => ['unit' => 'px', 'size' => 200],
330 'selectors' => [
331 '{{WRAPPER}} .marqueex-team-member-image img' => 'width: {{SIZE}}{{UNIT}};',
332 ],
333 ]
334 );
335
336 $this->add_responsive_control(
337 'image_spacing',
338 [
339 'label' => __('Spacing', 'marqueex'),
340 'type' => Controls_Manager::SLIDER,
341 'size_units' => ['px'],
342 'range' => ['px' => ['min' => 0, 'max' => 100]],
343 'default' => ['size' => 20, 'unit' => 'px'],
344 'selectors' => [
345 '{{WRAPPER}} .marqueex-team-member-image' => 'margin-bottom: {{SIZE}}{{UNIT}};',
346 ],
347 ]
348 );
349
350 $this->add_group_control(
351 Group_Control_Border::get_type(),
352 [
353 'name' => 'image_border',
354 'selector' => '{{WRAPPER}} .marqueex-team-member-image img',
355 ]
356 );
357
358 $this->add_responsive_control(
359 'image_border_radius',
360 [
361 'label' => __('Border Radius', 'marqueex'),
362 'type' => Controls_Manager::DIMENSIONS,
363 'size_units' => ['px', '%'],
364 'selectors' => [
365 '{{WRAPPER}} .marqueex-team-member-image, {{WRAPPER}} .marqueex-team-member-image img' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
366 ],
367 ]
368 );
369
370 $this->add_group_control(
371 Group_Control_Box_Shadow::get_type(),
372 [
373 'name' => 'image_box_shadow',
374 'selector' => '{{WRAPPER}} .marqueex-team-member-image img',
375 ]
376 );
377
378 $this->end_controls_section();
379
380 $this->start_controls_section(
381 'name_style_section',
382 [
383 'label' => __('Name', 'marqueex'),
384 'tab' => Controls_Manager::TAB_STYLE,
385 ]
386 );
387
388 $this->add_control(
389 'name_color',
390 [
391 'label' => __('Color', 'marqueex'),
392 'type' => Controls_Manager::COLOR,
393 'selectors' => [
394 '{{WRAPPER}} .marqueex-team-member-name' => 'color: {{VALUE}};',
395 ],
396 ]
397 );
398
399 $this->add_group_control(
400 Group_Control_Typography::get_type(),
401 [
402 'name' => 'name_typography',
403 'selector' => '{{WRAPPER}} .marqueex-team-member-name',
404 ]
405 );
406
407 $this->add_responsive_control(
408 'name_spacing',
409 [
410 'label' => __('Spacing', 'marqueex'),
411 'type' => Controls_Manager::SLIDER,
412 'size_units' => ['px'],
413 'range' => ['px' => ['min' => 0, 'max' => 50]],
414 'default' => ['size' => 10, 'unit' => 'px'],
415 'selectors' => [
416 '{{WRAPPER}} .marqueex-team-member-name' => 'margin-bottom: {{SIZE}}{{UNIT}};',
417 ],
418 ]
419 );
420
421 $this->end_controls_section();
422
423 $this->start_controls_section(
424 'role_style_section',
425 [
426 'label' => __('Job Role', 'marqueex'),
427 'tab' => Controls_Manager::TAB_STYLE,
428 ]
429 );
430
431 $this->add_control(
432 'role_color',
433 [
434 'label' => __('Color', 'marqueex'),
435 'type' => Controls_Manager::COLOR,
436 'selectors' => [
437 '{{WRAPPER}} .marqueex-team-member-role' => 'color: {{VALUE}};',
438 ],
439 ]
440 );
441
442 $this->add_group_control(
443 Group_Control_Typography::get_type(),
444 [
445 'name' => 'role_typography',
446 'selector' => '{{WRAPPER}} .marqueex-team-member-role',
447 ]
448 );
449
450 $this->end_controls_section();
451 }
452
453 /**
454 * Ensure minimum items for smooth marquee animation
455 */
456 private function ensure_minimum_posts($posts) {
457 if (empty($posts)) {
458 return [];
459 }
460
461 // Duplicate posts if we have less than 10 for smooth marquee
462 while (count($posts) < 10) {
463 $posts = array_merge($posts, $posts);
464 }
465
466 return $posts;
467 }
468
469 /**
470 * Prepare widget configuration from settings
471 */
472 private function prepare_widget_config($settings) {
473 return [
474 'unique_id' => 'marqueex-team-' . $this->get_id(),
475 'speed' => max(10, min(400, intval($settings['speed']['size'] ?? 20))),
476 'orientation' => $settings['orientation'] ?? 'horizontal',
477 'pause_on_hover' => $settings['pause'] === 'yes' ? 'true' : 'false',
478 'reverse_direction' => $settings['reverse'] === 'yes',
479 ];
480 }
481
482 /**
483 * Render team members content
484 */
485 private function render_team_members_content($settings) {
486 if (empty($settings['team_members'])) {
487 return;
488 }
489
490 $team_members = $this->ensure_minimum_posts($settings['team_members']);
491
492 echo '<div class="marqueex-marquee-wrapper">';
493 foreach ($team_members as $index => $member) {
494 $this->render_single_team_member($member, $settings, $index);
495 }
496 echo '</div>';
497 }
498
499 /**
500 * Render single team member
501 */
502 private function render_single_team_member($member, $settings, $index) {
503 $member_classes = 'marqueex-team-member';
504 if ('grayscale' === $settings['image_effect']) {
505 $member_classes .= ' marqueex-grayscale';
506 }
507 ?>
508 <div class="<?php echo esc_attr($member_classes); ?>">
509 <div class="marqueex-team-member-content">
510 <?php if (!empty($member['member_image']['url'])) : ?>
511 <div class="marqueex-team-member-image">
512 <?php
513 // Returns a complete, safe <img> built by Elementor's image-size group control.
514 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
515 echo Group_Control_Image_Size::get_attachment_image_html(
516 $member,
517 'thumbnail',
518 'member_image'
519 );
520 ?>
521 </div>
522 <?php endif; ?>
523
524 <?php if (!empty($member['member_name'])) : ?>
525 <h3 class="marqueex-team-member-name">
526 <?php echo esc_html($member['member_name']); ?>
527 </h3>
528 <?php endif; ?>
529
530 <?php if (!empty($member['member_role'])) : ?>
531 <div class="marqueex-team-member-role">
532 <?php echo esc_html($member['member_role']); ?>
533 </div>
534 <?php endif; ?>
535 </div>
536 </div>
537 <?php
538 }
539
540 /**
541 * Render widget output on the frontend
542 */
543 protected function render() {
544 $settings = $this->get_settings_for_display();
545 $widget_config = $this->prepare_widget_config($settings);
546
547 $this->add_render_attribute(
548 [
549 'marqueex-marquee-block' => [
550 'class' => [
551 'marqueex-marquee-block',
552 'marqueex-team-members-marquee',
553 $settings['pause'] === 'yes' ? 'is-paused' : '',
554 $settings['reverse'] === 'yes' ? 'is-reversed' : '',
555 $settings['orientation'] === 'vertical' ? 'marqueex-marquee-vertical' : 'marqueex-marquee-horizontal',
556 $settings['mask_edges'] === 'yes' ? 'marqueex-mask-edges' : '',
557 ],
558 'data-speed' => $widget_config['speed'],
559 'role' => 'region',
560 'aria-label' => __('Team Members Marquee', 'marqueex'),
561 ]
562 ]
563 );
564
565 ?>
566 <?php // get_render_attribute_string() returns markup already escaped by Elementor. ?>
567 <div <?php echo $this->get_render_attribute_string('marqueex-marquee-block'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
568 <div class="marqueex-marquee-track-wrapper">
569 <div class="marqueex-marquee-track">
570 <?php $this->render_team_members_content($settings); ?>
571 </div>
572 <div aria-hidden="true" class="marqueex-marquee-track">
573 <?php $this->render_team_members_content($settings); ?>
574 </div>
575 </div>
576 </div>
577
578 <?php
579 }
580 }
581