PluginProbe
Elementor Website Builder – more than just a page builder / 3.31.1
Elementor Website Builder – more than just a page builder v3.31.1
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / includes / widgets / heading.php

heading.php in Elementor Website Builder – more than just a page builder 3.31.1, at includes/widgets/heading.php

489 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit; // Exit if accessed directly.
6 }
7
8 use Elementor\Core\Kits\Documents\Tabs\Global_Colors;
9 use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
10 use Elementor\Modules\ContentSanitizer\Interfaces\Sanitizable;
11 use Elementor\Modules\Promotions\Controls\Promotion_Control;
12
13 /**
14 * Elementor heading widget.
15 *
16 * Elementor widget that displays an eye-catching headlines.
17 *
18 * @since 1.0.0
19 */
20 class Widget_Heading extends Widget_Base implements Sanitizable {
21
22 /**
23 * Get widget name.
24 *
25 * Retrieve heading widget name.
26 *
27 * @since 1.0.0
28 * @access public
29 *
30 * @return string Widget name.
31 */
32 public function get_name() {
33 return 'heading';
34 }
35
36 /**
37 * Get widget title.
38 *
39 * Retrieve heading widget title.
40 *
41 * @since 1.0.0
42 * @access public
43 *
44 * @return string Widget title.
45 */
46 public function get_title() {
47 return esc_html__( 'Heading', 'elementor' );
48 }
49
50 /**
51 * Get widget icon.
52 *
53 * Retrieve heading widget icon.
54 *
55 * @since 1.0.0
56 * @access public
57 *
58 * @return string Widget icon.
59 */
60 public function get_icon() {
61 return 'eicon-t-letter';
62 }
63
64 /**
65 * Get widget categories.
66 *
67 * Retrieve the list of categories the heading widget belongs to.
68 *
69 * Used to determine where to display the widget in the editor.
70 *
71 * @since 2.0.0
72 * @access public
73 *
74 * @return array Widget categories.
75 */
76 public function get_categories() {
77 return [ 'basic' ];
78 }
79
80 /**
81 * Get widget keywords.
82 *
83 * Retrieve the list of keywords the widget belongs to.
84 *
85 * @since 2.1.0
86 * @access public
87 *
88 * @return array Widget keywords.
89 */
90 public function get_keywords() {
91 return [ 'heading', 'title', 'text' ];
92 }
93
94 protected function is_dynamic_content(): bool {
95 return false;
96 }
97
98 /**
99 * Get style dependencies.
100 *
101 * Retrieve the list of style dependencies the widget requires.
102 *
103 * @since 3.24.0
104 * @access public
105 *
106 * @return array Widget style dependencies.
107 */
108 public function get_style_depends(): array {
109 return [ 'widget-heading' ];
110 }
111
112 public function has_widget_inner_wrapper(): bool {
113 return ! Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' );
114 }
115
116 /**
117 * Remove data attributes from the html.
118 *
119 * @param string $content Heading title.
120 * @return string
121 */
122 public function sanitize( $content ): string {
123 $allowed_tags = wp_kses_allowed_html( 'post' );
124 $allowed_tags_for_heading = [];
125 $non_allowed_tags = [ 'img' ];
126
127 foreach ( $allowed_tags as $tag => $attributes ) {
128 if ( in_array( $tag, $non_allowed_tags, true ) ) {
129 continue;
130 }
131
132 $filtered_attributes = array_filter( $attributes, function( $attribute ) {
133 return ! substr( $attribute, 0, 5 ) === 'data-';
134 }, ARRAY_FILTER_USE_KEY );
135
136 $allowed_tags_for_heading[ $tag ] = $filtered_attributes;
137 }
138
139 return wp_kses( $content, $allowed_tags_for_heading );
140 }
141
142 /**
143 * Get widget upsale data.
144 *
145 * Retrieve the widget promotion data.
146 *
147 * @since 3.18.0
148 * @access protected
149 *
150 * @return array Widget promotion data.
151 */
152 protected function get_upsale_data() {
153 return [
154 'condition' => ! Utils::has_pro(),
155 'image' => esc_url( ELEMENTOR_ASSETS_URL . 'images/go-pro.svg' ),
156 'image_alt' => esc_attr__( 'Upgrade', 'elementor' ),
157 'description' => esc_html__( 'Create captivating headings that rotate with the Animated Headline Widget.', 'elementor' ),
158 'upgrade_url' => esc_url( 'https://go.elementor.com/go-pro-heading-widget/' ),
159 'upgrade_text' => esc_html__( 'Upgrade Now', 'elementor' ),
160 ];
161 }
162
163 /**
164 * Register heading widget controls.
165 *
166 * Adds different input fields to allow the user to change and customize the widget settings.
167 *
168 * @since 3.1.0
169 * @access protected
170 */
171 protected function register_controls() {
172 $this->start_controls_section(
173 'section_title',
174 [
175 'label' => esc_html__( 'Heading', 'elementor' ),
176 ]
177 );
178
179 $this->add_control(
180 'title',
181 [
182 'label' => esc_html__( 'Title', 'elementor' ),
183 'type' => Controls_Manager::TEXTAREA,
184 'ai' => [
185 'type' => 'text',
186 ],
187 'dynamic' => [
188 'active' => true,
189 ],
190 'placeholder' => esc_html__( 'Enter your title', 'elementor' ),
191 'default' => esc_html__( 'Add Your Heading Text Here', 'elementor' ),
192 ]
193 );
194
195 $this->add_control(
196 'link',
197 [
198 'label' => esc_html__( 'Link', 'elementor' ),
199 'type' => Controls_Manager::URL,
200 'dynamic' => [
201 'active' => true,
202 ],
203 'default' => [
204 'url' => '',
205 ],
206 ]
207 );
208
209 $this->add_control(
210 'size',
211 [
212 'label' => esc_html__( 'Size', 'elementor' ),
213 'type' => Controls_Manager::SELECT,
214 'options' => [
215 'default' => esc_html__( 'Default', 'elementor' ),
216 'small' => esc_html__( 'Small', 'elementor' ),
217 'medium' => esc_html__( 'Medium', 'elementor' ),
218 'large' => esc_html__( 'Large', 'elementor' ),
219 'xl' => esc_html__( 'XL', 'elementor' ),
220 'xxl' => esc_html__( 'XXL', 'elementor' ),
221 ],
222 'default' => 'default',
223 'condition' => [
224 'size!' => 'default', // a workaround to hide the control, unless it's in use (not default).
225 ],
226 ]
227 );
228
229 $this->add_control(
230 'header_size',
231 [
232 'label' => esc_html__( 'HTML Tag', 'elementor' ),
233 'type' => Controls_Manager::SELECT,
234 'options' => [
235 'h1' => 'H1',
236 'h2' => 'H2',
237 'h3' => 'H3',
238 'h4' => 'H4',
239 'h5' => 'H5',
240 'h6' => 'H6',
241 'div' => 'div',
242 'span' => 'span',
243 'p' => 'p',
244 ],
245 'default' => 'h2',
246 ]
247 );
248
249 $this->end_controls_section();
250
251 $this->start_controls_section(
252 'section_title_style',
253 [
254 'label' => esc_html__( 'Heading', 'elementor' ),
255 'tab' => Controls_Manager::TAB_STYLE,
256 ]
257 );
258
259 $this->add_responsive_control(
260 'align',
261 [
262 'label' => esc_html__( 'Alignment', 'elementor' ),
263 'type' => Controls_Manager::CHOOSE,
264 'options' => [
265 'left' => [
266 'title' => esc_html__( 'Left', 'elementor' ),
267 'icon' => 'eicon-text-align-left',
268 ],
269 'center' => [
270 'title' => esc_html__( 'Center', 'elementor' ),
271 'icon' => 'eicon-text-align-center',
272 ],
273 'right' => [
274 'title' => esc_html__( 'Right', 'elementor' ),
275 'icon' => 'eicon-text-align-right',
276 ],
277 'justify' => [
278 'title' => esc_html__( 'Justified', 'elementor' ),
279 'icon' => 'eicon-text-align-justify',
280 ],
281 ],
282 'default' => '',
283 'selectors' => [
284 '{{WRAPPER}}' => 'text-align: {{VALUE}};',
285 ],
286 'separator' => 'after',
287 ]
288 );
289
290 $this->add_group_control(
291 Group_Control_Typography::get_type(),
292 [
293 'name' => 'typography',
294 'global' => [
295 'default' => Global_Typography::TYPOGRAPHY_PRIMARY,
296 ],
297 'selector' => '{{WRAPPER}} .elementor-heading-title',
298 ]
299 );
300
301 $this->add_group_control(
302 Group_Control_Text_Stroke::get_type(),
303 [
304 'name' => 'text_stroke',
305 'selector' => '{{WRAPPER}} .elementor-heading-title',
306 ]
307 );
308
309 $this->add_group_control(
310 Group_Control_Text_Shadow::get_type(),
311 [
312 'name' => 'text_shadow',
313 'selector' => '{{WRAPPER}} .elementor-heading-title',
314 ]
315 );
316
317 $this->add_control(
318 'blend_mode',
319 [
320 'label' => esc_html__( 'Blend Mode', 'elementor' ),
321 'type' => Controls_Manager::SELECT,
322 'options' => [
323 '' => esc_html__( 'Normal', 'elementor' ),
324 'multiply' => esc_html__( 'Multiply', 'elementor' ),
325 'screen' => esc_html__( 'Screen', 'elementor' ),
326 'overlay' => esc_html__( 'Overlay', 'elementor' ),
327 'darken' => esc_html__( 'Darken', 'elementor' ),
328 'lighten' => esc_html__( 'Lighten', 'elementor' ),
329 'color-dodge' => esc_html__( 'Color Dodge', 'elementor' ),
330 'saturation' => esc_html__( 'Saturation', 'elementor' ),
331 'color' => esc_html__( 'Color', 'elementor' ),
332 'difference' => esc_html__( 'Difference', 'elementor' ),
333 'exclusion' => esc_html__( 'Exclusion', 'elementor' ),
334 'hue' => esc_html__( 'Hue', 'elementor' ),
335 'luminosity' => esc_html__( 'Luminosity', 'elementor' ),
336 ],
337 'selectors' => [
338 '{{WRAPPER}} .elementor-heading-title' => 'mix-blend-mode: {{VALUE}}',
339 ],
340 ]
341 );
342
343 $this->add_control(
344 'separator',
345 [
346 'type' => Controls_Manager::DIVIDER,
347 ]
348 );
349
350 $this->start_controls_tabs( 'title_colors' );
351
352 $this->start_controls_tab(
353 'title_colors_normal',
354 [
355 'label' => esc_html__( 'Normal', 'elementor' ),
356 ]
357 );
358
359 $this->add_control(
360 'title_color',
361 [
362 'label' => esc_html__( 'Text Color', 'elementor' ),
363 'type' => Controls_Manager::COLOR,
364 'global' => [
365 'default' => Global_Colors::COLOR_PRIMARY,
366 ],
367 'selectors' => [
368 '{{WRAPPER}} .elementor-heading-title' => 'color: {{VALUE}};',
369 ],
370 ]
371 );
372
373 $this->end_controls_tab();
374
375 $this->start_controls_tab(
376 'title_colors_hover',
377 [
378 'label' => esc_html__( 'Hover', 'elementor' ),
379 ]
380 );
381
382 $this->add_control(
383 'title_hover_color',
384 [
385 'label' => esc_html__( 'Link Color', 'elementor' ),
386 'type' => Controls_Manager::COLOR,
387 'selectors' => [
388 '{{WRAPPER}} .elementor-heading-title a:hover, {{WRAPPER}} .elementor-heading-title a:focus' => 'color: {{VALUE}};',
389 ],
390 ]
391 );
392
393 $this->add_control(
394 'title_hover_color_transition_duration',
395 [
396 'label' => esc_html__( 'Transition Duration', 'elementor' ),
397 'type' => Controls_Manager::SLIDER,
398 'size_units' => [ 's', 'ms', 'custom' ],
399 'default' => [
400 'unit' => 's',
401 ],
402 'selectors' => [
403 '{{WRAPPER}} .elementor-heading-title a' => 'transition-duration: {{SIZE}}{{UNIT}};',
404 ],
405 ]
406 );
407
408 $this->end_controls_tab();
409
410 $this->end_controls_tabs();
411
412 $this->end_controls_section();
413 }
414
415 /**
416 * Render heading widget output on the frontend.
417 *
418 * Written in PHP and used to generate the final HTML.
419 *
420 * @since 1.0.0
421 * @access protected
422 */
423 protected function render() {
424 $settings = $this->get_settings_for_display();
425
426 if ( '' === $settings['title'] ) {
427 return;
428 }
429
430 $this->add_render_attribute( 'title', 'class', 'elementor-heading-title' );
431
432 if ( ! empty( $settings['size'] ) ) {
433 $this->add_render_attribute( 'title', 'class', 'elementor-size-' . $settings['size'] );
434 } else {
435 $this->add_render_attribute( 'title', 'class', 'elementor-size-default' );
436 }
437
438 $this->add_inline_editing_attributes( 'title' );
439
440 $title = wp_kses_post( $settings['title'] );
441
442 if ( ! empty( $settings['link']['url'] ) ) {
443 $this->add_link_attributes( 'url', $settings['link'] );
444
445 $title = sprintf( '<a %1$s>%2$s</a>', $this->get_render_attribute_string( 'url' ), $title );
446 }
447
448 $title_html = sprintf( '<%1$s %2$s>%3$s</%1$s>', Utils::validate_html_tag( $settings['header_size'] ), $this->get_render_attribute_string( 'title' ), $title );
449
450 // PHPCS - the variable $title_html holds safe data.
451 echo $title_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
452 }
453
454 /**
455 * Render heading widget output in the editor.
456 *
457 * Written as a Backbone JavaScript template and used to generate the live preview.
458 *
459 * @since 2.9.0
460 * @access protected
461 */
462 protected function content_template() {
463 ?>
464 <#
465 let title = elementor.helpers.sanitize( settings.title, { ALLOW_DATA_ATTR: false } );
466
467 if ( '' !== settings.link.url ) {
468 title = '<a href="' + elementor.helpers.sanitizeUrl( settings.link.url ) + '">' + title + '</a>';
469 }
470
471 view.addRenderAttribute( 'title', 'class', [ 'elementor-heading-title' ] );
472
473 if ( '' !== settings.size ) {
474 view.addRenderAttribute( 'title', 'class', [ 'elementor-size-' + settings.size ] );
475 } else {
476 view.addRenderAttribute( 'title', 'class', [ 'elementor-size-default' ] );
477 }
478
479 view.addInlineEditingAttributes( 'title' );
480
481 var headerSizeTag = elementor.helpers.validateHTMLTag( settings.header_size ),
482 title_html = '<' + headerSizeTag + ' ' + view.getRenderAttributeString( 'title' ) + '>' + title + '</' + headerSizeTag + '>';
483
484 print( title_html );
485 #>
486 <?php
487 }
488 }
489