Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 126
0.00% covered (danger)
0.00%
0 / 5
CRAP
n/a
0 / 0
Automattic\Jetpack\Extensions\Calendly\register_block
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
Automattic\Jetpack\Extensions\Calendly\load_assets
0.00% covered (danger)
0.00%
0 / 68
0.00% covered (danger)
0.00%
0 / 1
132
Automattic\Jetpack\Extensions\Calendly\get_attribute
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
Automattic\Jetpack\Extensions\Calendly\enqueue_calendly_js
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
Automattic\Jetpack\Extensions\Calendly\deprecated_render_button_v1
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2/**
3 * Calendly Block.
4 *
5 * @since 8.2.0
6 *
7 * @package automattic/jetpack
8 */
9
10namespace Automattic\Jetpack\Extensions\Calendly;
11
12use Automattic\Jetpack\Blocks;
13use Jetpack_Gutenberg;
14
15if ( ! defined( 'ABSPATH' ) ) {
16    exit( 0 );
17}
18
19/**
20 * Registers the block for use in Gutenberg
21 * This is done via an action so that we can disable
22 * registration if we need to.
23 */
24function register_block() {
25    Blocks::jetpack_register_block(
26        __DIR__,
27        array(
28            'render_callback' => __NAMESPACE__ . '\load_assets',
29            'plan_check'      => true,
30        )
31    );
32}
33add_action( 'init', __NAMESPACE__ . '\register_block' );
34
35/**
36 * Calendly block registration/dependency declaration.
37 *
38 * @param array  $attr    Array containing the Calendly block attributes.
39 * @param string $content String containing the Calendly block content.
40 *
41 * @return string
42 */
43function load_assets( $attr, $content ) {
44
45    if ( is_admin() ) {
46        return;
47    }
48    $url = Jetpack_Gutenberg::validate_block_embed_url(
49        get_attribute( $attr, 'url' ),
50        array( 'calendly.com' )
51    );
52    if ( empty( $url ) ) {
53        return;
54    }
55
56    /*
57     * Enqueue necessary scripts and styles.
58     */
59    Jetpack_Gutenberg::load_assets_as_required( __DIR__ );
60
61    $style                   = get_attribute( $attr, 'style' );
62    $hide_event_type_details = get_attribute( $attr, 'hideEventTypeDetails' );
63    $background_color        = get_attribute( $attr, 'backgroundColor' );
64    $text_color              = get_attribute( $attr, 'textColor' );
65    $primary_color           = get_attribute( $attr, 'primaryColor' );
66    $classes                 = Blocks::classes( Blocks::get_block_feature( __DIR__ ), $attr, array( 'calendly-style-' . $style ) );
67    $block_id                = wp_unique_id( 'calendly-block-' );
68    $is_amp_request          = Blocks::is_amp_request();
69
70    if ( ! wp_script_is( 'jetpack-calendly-external-js' ) && ! $is_amp_request ) {
71        enqueue_calendly_js();
72    }
73
74    $base_url = $url;
75    $url      = add_query_arg(
76        array(
77            'hide_event_type_details' => (int) $hide_event_type_details,
78            'background_color'        => sanitize_hex_color_no_hash( $background_color ),
79            'text_color'              => sanitize_hex_color_no_hash( $text_color ),
80            'primary_color'           => sanitize_hex_color_no_hash( $primary_color ),
81        ),
82        $url
83    );
84
85    if ( 'link' === $style ) {
86        if ( ! wp_style_is( 'jetpack-calendly-external-css' ) ) {
87            wp_enqueue_style( 'jetpack-calendly-external-css', 'https://assets.calendly.com/assets/external/widget.css', null, JETPACK__VERSION );
88        }
89
90        // Render deprecated version of Calendly block if needed. New markup block button class before rendering here.
91        if ( ! str_contains( $content, 'wp-block-jetpack-button' ) ) {
92            $content = deprecated_render_button_v1( $attr, $block_id, $classes, $url );
93        } else {
94            $content = str_replace( 'calendly-widget-id', esc_attr( $block_id ), $content );
95            $content = str_replace( $base_url, $url, $content );
96        }
97
98        if ( ! $is_amp_request ) {
99            wp_add_inline_script(
100                'jetpack-calendly-external-js',
101                sprintf( 'calendly_attach_link_events( %s )', wp_json_encode( $block_id, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) )
102            );
103        }
104    } elseif ( $is_amp_request ) { // Inline style.
105        $content = sprintf(
106            '<div class="%1$s" id="%2$s"><a href="%3$s" role="button" target="_blank">%4$s</a></div>',
107            esc_attr( Blocks::classes( Blocks::get_block_feature( __DIR__ ), $attr ) ),
108            esc_attr( $block_id ),
109            esc_attr( $url ),
110            wp_kses_post( get_attribute( $attr, 'submitButtonText' ) )
111        );
112    } else {
113        $content           = sprintf(
114            '<div class="%1$s" id="%2$s"></div>',
115            esc_attr( $classes ),
116            esc_attr( $block_id )
117        );
118        $script            = <<<'JS_END'
119jetpackInitCalendly( %s, %s );
120JS_END;
121        $json_encode_flags = JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP;
122        if ( get_option( 'blog_charset' ) === 'UTF-8' ) {
123            $json_encode_flags |= JSON_UNESCAPED_UNICODE;
124        }
125        wp_add_inline_script(
126            'jetpack-calendly-external-js',
127            sprintf(
128                $script,
129                wp_json_encode( esc_url_raw( $url ), $json_encode_flags ),
130                wp_json_encode( $block_id, $json_encode_flags )
131            )
132        );
133    }
134
135    return $content;
136}
137
138/**
139 * Get filtered attributes.
140 *
141 * @param array  $attributes     Array containing the Calendly block attributes.
142 * @param string $attribute_name String containing the attribute name to get.
143 *
144 * @return string
145 */
146function get_attribute( $attributes, $attribute_name ) {
147    if ( isset( $attributes[ $attribute_name ] ) ) {
148        return $attributes[ $attribute_name ];
149    }
150
151    $default_attributes = array(
152        'style'                => 'inline',
153        'submitButtonText'     => esc_html__( 'Schedule time with me', 'jetpack' ),
154        'backgroundColor'      => 'ffffff',
155        'textColor'            => '4D5055',
156        'primaryColor'         => '00A2FF',
157        'hideEventTypeDetails' => false,
158    );
159
160    if ( isset( $default_attributes[ $attribute_name ] ) ) {
161        return $default_attributes[ $attribute_name ];
162    }
163}
164
165/**
166 * Enqueues the Calendly JS library and inline function to attach event
167 * handlers to the button.
168 *
169 * @return void
170 */
171function enqueue_calendly_js() {
172    wp_enqueue_script(
173        'jetpack-calendly-external-js',
174        'https://assets.calendly.com/assets/external/widget.js',
175        null,
176        JETPACK__VERSION,
177        false
178    );
179
180    wp_add_inline_script(
181        'jetpack-calendly-external-js',
182        "function jetpackInitCalendly( url, elementId ) {
183            function initCalendlyWidget() {
184                if ( ! document.getElementById( elementId ) ) {
185                    return;
186                }
187                Calendly.initInlineWidget({
188                    url: url,
189                    parentElement: document.getElementById( elementId ),
190                    inlineStyles: false,
191                });
192            };
193            // For P2s only: wait until after o2 has
194            // replaced main#content to initialize widget.
195            if ( window.jQuery && window.o2 ) {
196                jQuery( 'body' ).on( 'ready_o2', function() { initCalendlyWidget() } );
197            // Else initialize widget without waiting.
198            } else {
199                document.addEventListener('DOMContentLoaded', function() {
200                    initCalendlyWidget();
201                });
202            }
203        };
204
205        function calendly_attach_link_events( elementId ) {
206            var widget = document.getElementById( elementId );
207            if ( widget ) {
208                widget.addEventListener( 'click', function( event ) {
209                    event.preventDefault();
210                    Calendly.initPopupWidget( { url: event.target.href } );
211                } );
212                widget.addEventListener( 'keydown', function( event ) {
213                    // Enter and space keys.
214                    if ( event.keyCode === 13 || event.keyCode === 32 ) {
215                        event.preventDefault();
216                        event.target && event.target.click();
217                    }
218                } );
219            }
220        }"
221    );
222}
223
224/**
225 * Renders a deprecated legacy version of the button HTML.
226 *
227 * @param array  $attributes Array containing the Calendly block attributes.
228 * @param string $block_id  The value for the ID attribute of the link.
229 * @param string $classes   The CSS classes for the wrapper div.
230 * @param string $url       Calendly URL for the link HREF.
231 *
232 * @return string
233 */
234function deprecated_render_button_v1( $attributes, $block_id, $classes, $url ) {
235    // This is the legacy version, so create the full link content.
236    $submit_button_text             = get_attribute( $attributes, 'submitButtonText' );
237    $submit_button_classes          = get_attribute( $attributes, 'submitButtonClasses' );
238    $submit_button_text_color       = get_attribute( $attributes, 'customTextButtonColor' );
239    $submit_button_background_color = get_attribute( $attributes, 'customBackgroundButtonColor' );
240
241    /*
242     * If we have some additional styles from the editor
243     * (a custom text color, custom bg color, or both )
244     * Let's add that CSS inline.
245     */
246    if ( ! empty( $submit_button_text_color ) || ! empty( $submit_button_background_color ) ) {
247        $inline_styles = sprintf(
248            '#%1$s{%2$s%3$s}',
249            esc_attr( $block_id ),
250            ! empty( $submit_button_text_color )
251                ? 'color:#' . sanitize_hex_color_no_hash( $submit_button_text_color ) . ';'
252                : '',
253            ! empty( $submit_button_background_color )
254                ? 'background-color:#' . sanitize_hex_color_no_hash( $submit_button_background_color ) . ';'
255                : ''
256        );
257        wp_add_inline_style( 'jetpack-calendly-external-css', $inline_styles );
258    }
259
260    return sprintf(
261        '<div class="wp-block-button %1$s"><a id="%2$s" class="%3$s" href="%4$s" role="button">%5$s</a></div>',
262        esc_attr( $classes ),
263        esc_attr( $block_id ),
264        ! empty( $submit_button_classes ) ? esc_attr( $submit_button_classes ) : 'wp-block-button__link',
265        esc_attr( $url ),
266        wp_kses_post( $submit_button_text )
267    );
268}