PluginProbe ʕ •ᴥ•ʔ
ECS – Ele Custom Skin for Elementor / 4.3.6
ECS – Ele Custom Skin for Elementor v4.3.6
4.3.6 4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.11 4.1.10 4.1.9 4.1.8 4.1.6 4.1.7 4.1.5 4.1.4 4.1.1 4.1.2 trunk 1.0.0 1.0.1 1.0.9 1.1.3 1.1.4 1.1.5 1.2.0 1.2.1 1.2.4 1.2.5 1.3.10 1.3.11 1.3.3 1.3.4 1.3.6 1.3.7 1.3.9 1.4.0 2.0.2 2.1.0 2.2.0 2.2.1 2.2.2 3.0.0 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 4.1.0
ele-custom-skin / modules / editorial-text / widgets / class-ecs-editorial-text-widget.php
ele-custom-skin / modules / editorial-text / widgets Last commit date
class-ecs-editorial-text-widget.php 2 months ago
class-ecs-editorial-text-widget.php
323 lines
1 <?php
2 /**
3 * Elementor Widget: ECS Editorial Text
4 *
5 * Combines WYSIWYG content with an optional image.
6 * Image can flow as: none / before / after / float_left / float_right.
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 use Elementor\Widget_Base;
14 use Elementor\Controls_Manager;
15 use Elementor\Group_Control_Typography;
16 use Elementor\Group_Control_Image_Size;
17 use Elementor\Group_Control_Box_Shadow;
18 use Elementor\Group_Control_Border;
19
20 class ECS_Editorial_Text_Widget extends Widget_Base {
21
22 public function get_name(): string {
23 return 'ecs_editorial_text';
24 }
25
26 public function get_title(): string {
27 return esc_html__( 'ECS Editorial Text', 'ele-custom-skin' );
28 }
29
30 public function get_icon(): string {
31 return 'eicon-text-area';
32 }
33
34 public function get_categories(): array {
35 return [ 'ele-custom-skin' ];
36 }
37
38 public function get_keywords(): array {
39 return [ 'ecs', 'editorial', 'text', 'image', 'float', 'wysiwyg', 'wrap' ];
40 }
41
42 protected function register_controls(): void {
43 $this->register_content_controls();
44 $this->register_image_settings_controls();
45 $this->register_style_text_controls();
46 $this->register_style_image_controls();
47 }
48
49 // ── Content Tab ───────────────────────────────────────────────────────────
50
51 private function register_content_controls(): void {
52
53 $this->start_controls_section( 'section_content', [
54 'label' => esc_html__( 'Content', 'ele-custom-skin' ),
55 'tab' => Controls_Manager::TAB_CONTENT,
56 ] );
57
58 $this->add_control( 'ecs_et_text', [
59 'label' => esc_html__( 'Text', 'ele-custom-skin' ),
60 'type' => Controls_Manager::WYSIWYG,
61 'default' => '<p>' . esc_html__( 'Enter your editorial text here. This text can wrap around the image when a float mode is selected.', 'ele-custom-skin' ) . '</p>',
62 'dynamic' => [ 'active' => true ],
63 ] );
64
65 $this->add_control( 'ecs_et_image', [
66 'label' => esc_html__( 'Image', 'ele-custom-skin' ),
67 'type' => Controls_Manager::MEDIA,
68 'default' => [ 'url' => '' ],
69 'dynamic' => [ 'active' => true ],
70 ] );
71
72 $this->add_responsive_control( 'ecs_et_image_flow', [
73 'label' => esc_html__( 'Image Position', 'ele-custom-skin' ),
74 'type' => Controls_Manager::SELECT,
75 'default' => 'float_left',
76 'options' => [
77 'none' => esc_html__( 'None (block, above text)', 'ele-custom-skin' ),
78 'before' => esc_html__( 'Before Text', 'ele-custom-skin' ),
79 'after' => esc_html__( 'After Text', 'ele-custom-skin' ),
80 'float_left' => esc_html__( 'Float Left', 'ele-custom-skin' ),
81 'float_right' => esc_html__( 'Float Right', 'ele-custom-skin' ),
82 ],
83 'prefix_class' => 'e-et%s-flow-',
84 'condition' => [ 'ecs_et_image[url]!' => '' ],
85 ] );
86
87 $this->add_responsive_control( 'ecs_et_content_align', [
88 'label' => esc_html__( 'Content Align', 'ele-custom-skin' ),
89 'type' => Controls_Manager::CHOOSE,
90 'options' => [
91 'left' => [ 'title' => esc_html__( 'Left', 'ele-custom-skin' ), 'icon' => 'eicon-text-align-left' ],
92 'center' => [ 'title' => esc_html__( 'Center', 'ele-custom-skin' ), 'icon' => 'eicon-text-align-center' ],
93 'right' => [ 'title' => esc_html__( 'Right', 'ele-custom-skin' ), 'icon' => 'eicon-text-align-right' ],
94 'justify' => [ 'title' => esc_html__( 'Justify', 'ele-custom-skin' ), 'icon' => 'eicon-text-align-justify' ],
95 ],
96 'prefix_class' => 'e-et%s-align-',
97 ] );
98
99 $this->end_controls_section();
100 }
101
102 // ── Image Settings Section (Content Tab) ──────────────────────────────────
103 // Keeps only the WP image size selector — all visual styling is in Style > Image.
104
105 private function register_image_settings_controls(): void {
106
107 $this->start_controls_section( 'section_image_settings', [
108 'label' => esc_html__( 'Image Settings', 'ele-custom-skin' ),
109 'tab' => Controls_Manager::TAB_CONTENT,
110 'condition' => [ 'ecs_et_image[url]!' => '' ],
111 ] );
112
113 // 'name' => 'ecs_et_image' generates ecs_et_image_size + ecs_et_image_custom_dimension,
114 // both read by Group_Control_Image_Size::get_attachment_image_html().
115 $this->add_group_control( Group_Control_Image_Size::get_type(), [
116 'name' => 'ecs_et_image',
117 'default' => 'large',
118 ] );
119
120 $this->end_controls_section();
121 }
122
123 // ── Style Tab — Text ──────────────────────────────────────────────────────
124
125 private function register_style_text_controls(): void {
126
127 $this->start_controls_section( 'section_style_text', [
128 'label' => esc_html__( 'Text', 'ele-custom-skin' ),
129 'tab' => Controls_Manager::TAB_STYLE,
130 ] );
131
132 $this->add_group_control( Group_Control_Typography::get_type(), [
133 'name' => 'ecs_et_typography',
134 'selector' => '{{WRAPPER}} .ecs-et-text',
135 ] );
136
137 $this->add_control( 'ecs_et_color', [
138 'label' => esc_html__( 'Color', 'ele-custom-skin' ),
139 'type' => Controls_Manager::COLOR,
140 'selectors' => [ '{{WRAPPER}} .ecs-et-text' => 'color: {{VALUE}};' ],
141 ] );
142
143 $this->end_controls_section();
144 }
145
146 // ── Style Tab — Image ─────────────────────────────────────────────────────
147
148 private function register_style_image_controls(): void {
149
150 $this->start_controls_section( 'section_style_image', [
151 'label' => esc_html__( 'Image', 'ele-custom-skin' ),
152 'tab' => Controls_Manager::TAB_STYLE,
153 'condition' => [ 'ecs_et_image[url]!' => '' ],
154 ] );
155
156 // ── Distance from text ─────────────────────────────────────────────────
157 // Sets --ecs-et-gap CSS variable on the widget wrapper.
158 // CSS rules consume it on the correct margin side per flow direction:
159 // float_left → margin-right float_right → margin-left
160 // none/before → margin-bottom after → margin-top
161 $this->add_responsive_control( 'ecs_et_img_gap', [
162 'label' => esc_html__( 'Distance from Text', 'ele-custom-skin' ),
163 'type' => Controls_Manager::SLIDER,
164 'size_units' => [ 'px', 'em', '%' ],
165 'range' => [
166 'px' => [ 'min' => 0, 'max' => 200 ],
167 'em' => [ 'min' => 0, 'max' => 10, 'step' => 0.1 ],
168 '%' => [ 'min' => 0, 'max' => 50 ],
169 ],
170 'selectors' => [
171 '{{WRAPPER}}' => '--ecs-et-gap: {{SIZE}}{{UNIT}};',
172 ],
173 ] );
174
175 $this->add_control( 'ecs_et_img_gap_note', [
176 'type' => Controls_Manager::RAW_HTML,
177 'raw' => esc_html__( 'Float Left → right gap · Float Right → left gap · Before/None → bottom gap · After → top gap', 'ele-custom-skin' ),
178 'content_classes' => 'elementor-descriptor',
179 ] );
180
181 $this->add_control( 'ecs_et_style_divider_size', [
182 'type' => Controls_Manager::DIVIDER,
183 ] );
184
185 // ── Dimensions ────────────────────────────────────────────────────────
186
187 $this->add_responsive_control( 'ecs_et_img_width', [
188 'label' => esc_html__( 'Width', 'ele-custom-skin' ),
189 'type' => Controls_Manager::SLIDER,
190 'size_units' => [ 'px', '%' ],
191 'range' => [
192 'px' => [ 'min' => 50, 'max' => 1200 ],
193 '%' => [ 'min' => 5, 'max' => 100 ],
194 ],
195 'selectors' => [ '{{WRAPPER}} .ecs-et-figure' => 'width: {{SIZE}}{{UNIT}};' ],
196 ] );
197
198 $this->add_responsive_control( 'ecs_et_img_max_width', [
199 'label' => esc_html__( 'Max Width', 'ele-custom-skin' ),
200 'type' => Controls_Manager::SLIDER,
201 'size_units' => [ 'px', '%' ],
202 'range' => [
203 'px' => [ 'min' => 50, 'max' => 1200 ],
204 '%' => [ 'min' => 5, 'max' => 100 ],
205 ],
206 'selectors' => [ '{{WRAPPER}} .ecs-et-figure' => 'max-width: {{SIZE}}{{UNIT}};' ],
207 ] );
208
209 $this->add_responsive_control( 'ecs_et_img_height', [
210 'label' => esc_html__( 'Height', 'ele-custom-skin' ),
211 'type' => Controls_Manager::SLIDER,
212 'size_units' => [ 'px', 'vh', '%' ],
213 'range' => [
214 'px' => [ 'min' => 50, 'max' => 800 ],
215 'vh' => [ 'min' => 5, 'max' => 100 ],
216 '%' => [ 'min' => 5, 'max' => 100 ],
217 ],
218 // Set height on the figure container + make img fill it so object-fit works.
219 // When no height is set this selector generates no CSS → natural image sizing.
220 'selectors' => [
221 '{{WRAPPER}} .ecs-et-figure' => 'height: {{SIZE}}{{UNIT}}; overflow: hidden;',
222 '{{WRAPPER}} .ecs-et-figure img' => 'width: 100%; height: 100%;',
223 ],
224 ] );
225
226 $this->add_responsive_control( 'ecs_et_img_object_fit', [
227 'label' => esc_html__( 'Object Fit', 'ele-custom-skin' ),
228 'type' => Controls_Manager::SELECT,
229 'default' => '',
230 'options' => [
231 '' => esc_html__( 'Default', 'ele-custom-skin' ),
232 'cover' => esc_html__( 'Cover', 'ele-custom-skin' ),
233 'contain' => esc_html__( 'Contain', 'ele-custom-skin' ),
234 'fill' => esc_html__( 'Fill', 'ele-custom-skin' ),
235 ],
236 'selectors' => [ '{{WRAPPER}} .ecs-et-figure img' => 'object-fit: {{VALUE}};' ],
237 ] );
238
239 $this->add_control( 'ecs_et_style_divider_border', [
240 'type' => Controls_Manager::DIVIDER,
241 ] );
242
243 // ── Border & decoration ───────────────────────────────────────────────
244
245 $this->add_group_control( Group_Control_Border::get_type(), [
246 'name' => 'ecs_et_img_border',
247 'selector' => '{{WRAPPER}} .ecs-et-figure',
248 ] );
249
250 $this->add_responsive_control( 'ecs_et_img_border_radius', [
251 'label' => esc_html__( 'Border Radius', 'ele-custom-skin' ),
252 'type' => Controls_Manager::DIMENSIONS,
253 'size_units' => [ 'px', '%', 'em' ],
254 'selectors' => [
255 '{{WRAPPER}} .ecs-et-figure' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}}; overflow: hidden;',
256 '{{WRAPPER}} .ecs-et-figure img' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
257 ],
258 ] );
259
260 $this->add_group_control( Group_Control_Box_Shadow::get_type(), [
261 'name' => 'ecs_et_img_box_shadow',
262 'selector' => '{{WRAPPER}} .ecs-et-figure',
263 ] );
264
265 $this->end_controls_section();
266 }
267
268 // ── Render ────────────────────────────────────────────────────────────────
269
270 protected function render(): void {
271 $s = $this->get_settings_for_display();
272 $text = $s['ecs_et_text'] ?? '';
273 $has_image = ! empty( $s['ecs_et_image']['url'] );
274 ?>
275 <div class="ecs-editorial-text">
276
277 <?php if ( $has_image ) { $this->render_figure( $s ); } ?>
278
279 <div class="ecs-et-text">
280 <?php echo wp_kses_post( $text ); ?>
281 </div>
282
283 </div>
284 <?php
285 }
286
287 /**
288 * Output <figure> with the image at the user-selected size.
289 */
290 private function render_figure( array $s ): void {
291 $img_html = Group_Control_Image_Size::get_attachment_image_html(
292 $s,
293 'ecs_et_image', // reads $s['ecs_et_image_size'] + $s['ecs_et_image_custom_dimension']
294 'ecs_et_image' // reads $s['ecs_et_image']['id'] / ['url']
295 );
296
297 if ( empty( $img_html ) ) {
298 return;
299 }
300 ?>
301 <figure class="ecs-et-figure">
302 <?php
303 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
304 echo wp_kses( $img_html, [
305 'img' => [
306 'src' => [],
307 'srcset' => [],
308 'sizes' => [],
309 'alt' => [],
310 'title' => [],
311 'class' => [],
312 'loading' => [],
313 'width' => [],
314 'height' => [],
315 'decoding' => [],
316 ],
317 ] );
318 ?>
319 </figure>
320 <?php
321 }
322 }
323