'async', 'in_footer' => false, ) ); // phpcs:enable WordPress.WP.EnqueuedResourceParameters.MissingVersion return $registered; } /** * Whether the founder wants the loader on every page (on unless turned off). * * @return bool */ public static function load_everywhere() { $settings = get_option( self::SETTINGS, array() ); if ( ! is_array( $settings ) || ! array_key_exists( 'load_everywhere', $settings ) ) { return true; } return (bool) $settings['load_everywhere']; } /** * `wp_enqueue_scripts`: the loader on every page while connected and the setting is on, so * referral credit follows a visitor from page to page. Where the WP Consent API is active, only * after the visitor gave `marketing` consent. * * @return void */ public static function enqueue_everywhere() { $load = Connection::is_active() && self::load_everywhere() && self::has_consent(); /** * Filters whether the LaunchList loader is added to every front-end page. Pages with a * LaunchList block or shortcode load it either way. * * @since 1.0.0 * * @param bool $load True while the site is connected, "Load LaunchList on every page" is on, * and (where the WP Consent API is active) the visitor gave marketing consent. */ if ( apply_filters( 'launchlist_load_everywhere', $load ) ) { self::enqueue(); } } /** * Whether the visitor allowed marketing cookies: always, unless the WP Consent API is active and * says otherwise. * * @return bool */ public static function has_consent() { if ( function_exists( 'wp_has_consent' ) ) { return (bool) wp_has_consent( 'marketing' ); } return true; } /** * Enqueue the loader. * * @return void */ public static function enqueue() { if ( wp_script_is( self::HANDLE, 'registered' ) || self::register_script() ) { wp_enqueue_script( self::HANDLE ); } } /** * `script_loader_tag`: mark the loader as this plugin's while the site is connected (and, where * the WP Consent API is active, after marketing consent), which makes it keep the visitor's * attribution in a first-party cookie for the site's own forms (PROTOCOL.md §4). * * @param string $tag The script tag. * @param string $handle The handle. * @return string */ public static function script_tag( $tag, $handle ) { if ( self::HANDLE !== $handle || ! is_string( $tag ) || false !== strpos( $tag, 'data-launchlist-wordpress' ) || ! Connection::is_active() || ! self::has_consent() ) { return $tag; } return (string) preg_replace( '/ '', 'button' => '', 'popup' => '', 'label' => '', 'variant' => '', 'widget' => '', 'project' => '', 'updates' => '', ), is_array( $atts ) ? $atts : array(), 'launchlist' ); return self::render( self::from_shortcode( $atts ) ); } /** * The `launchlist/embed` block's render. * * @param array $attributes Block attributes. * @return string */ public static function render_block( $attributes ) { $html = self::render( self::from_block( is_array( $attributes ) ? $attributes : array() ) ); if ( '' === $html || 0 === strpos( $html, ''; } self::enqueue(); return $markup; } /** * The embed markup, every value checked against its pattern and escaped; `""` when invalid. * * @param array $args Render arguments. * @return string */ public static function markup( array $args ) { $args = array_merge( self::args(), $args ); switch ( $args['kind'] ) { case 'form': if ( ! self::valid_form_id( $args['form'] ) ) { return ''; } $button = self::label( $args['button'] ); return '
'; case 'popup': if ( ! self::valid_form_id( $args['form'] ) ) { return ''; } $label = self::label( $args['label'] ); $label = '' !== $label ? $label : __( 'Join the waitlist', 'launchlist' ); $variant = in_array( $args['variant'], self::VARIANTS, true ) ? $args['variant'] : 'modal'; return ''; case 'widget': if ( ! self::valid_widget( $args['widget'] ) || ! self::valid_slug( $args['project'] ) ) { return ''; } return '
'; case 'updates': if ( ! self::valid_slug( $args['project'] ) ) { return ''; } // No "Powered by LaunchList" credit: WordPress.org lets a plugin show one on the public // site only when the site owner asked for it (guideline 10). return '
'; } return ''; } /** * Whether a value is a form ID. * * @param mixed $value The value. * @return bool */ public static function valid_form_id( $value ) { return is_string( $value ) && 1 === preg_match( self::FORM_ID, $value ); } /** * Whether a value is a widget ID or a widget kind. * * @param mixed $value The value. * @return bool */ public static function valid_widget( $value ) { return is_string( $value ) && ( 1 === preg_match( self::WIDGET_ID, $value ) || 1 === preg_match( self::WIDGET_KEYWORD, $value ) ); } /** * Whether a value is a project slug. * * @param mixed $value The value. * @return bool */ public static function valid_slug( $value ) { return is_string( $value ) && 1 === preg_match( self::SLUG, $value ); } /** * Empty render arguments. * * @return array{kind: string, form: string, button: string, label: string, variant: string, widget: string, project: string} */ private static function args() { return array( 'kind' => '', 'form' => '', 'button' => '', 'label' => '', 'variant' => '', 'widget' => '', 'project' => '', ); } /** * A button label: plain text, at most 80 characters. * * @param mixed $value The value. * @return string */ private static function label( $value ) { return is_string( $value ) ? Connection::truncate( trim( sanitize_text_field( $value ) ), self::MAX_LABEL ) : ''; } /** * Why nothing renders, for people who can edit the page. * * @param array $args Render arguments. * @return string */ private static function problem( array $args ) { switch ( isset( $args['kind'] ) ? $args['kind'] : '' ) { case 'form': case 'popup': /* translators: %s: the form ID prefix. */ return sprintf( __( 'LaunchList: add a form ID that starts with %s to show this form. It is in LaunchList under Embed & API.', 'launchlist' ), 'frm_' ); case 'widget': /* translators: %s: the data-project attribute. */ return sprintf( __( 'LaunchList: add a widget and the %s value from a widget snippet in LaunchList to show this widget.', 'launchlist' ), 'data-project' ); case 'updates': /* translators: %s: the data-project attribute. */ return sprintf( __( 'LaunchList: add the %s value from a widget snippet in LaunchList to show your updates.', 'launchlist' ), 'data-project' ); } return __( 'LaunchList: choose a form, a popup, a widget or updates to show.', 'launchlist' ); } }