Skip to content

Commit

Permalink
Blocks: add a new Cookie Consent Block
Browse files Browse the repository at this point in the history
Replay of #29191 in the Jetpack plugin.

This adds a new Beta block, to be used in block themes, to display a cookie consent banner on the site.

Co-authored-by: Omar Alshaker <omar@omaralshaker.com>
  • Loading branch information
jeherve and alshakero committed Feb 28, 2023
1 parent 8fa35bc commit 747eae2
Show file tree
Hide file tree
Showing 13 changed files with 530 additions and 0 deletions.
4 changes: 4 additions & 0 deletions projects/plugins/jetpack/changelog/add-cookie-consent-block
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: enhancement

Blocks: add a new Cookie Consent block. Display a GDPR-compliant cookie consent widget on your site for your visitors.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { __ } from '@wordpress/i18n';

export default {
text: {
type: 'string',
source: 'html',
selector: 'p',
default: __(
'Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use. To find out more, including how to control cookies, see here: <a href=https://automattic.com/cookies/>Cookie Policy</a>.',
'jetpack'
),
},
style: {
type: 'object',
default: {
color: {
text: 'var(--wp--preset--color--contrast)',
background: 'var(--wp--preset--color--tertiary)',
link: 'var(--wp--preset--color--contrast)',
},
spacing: {
padding: {
top: '1em',
right: '1em',
bottom: '1em',
left: '1em',
},
},
},
},
align: {
type: 'string',
default: 'wide',
},
consentExpiryDays: {
type: 'integer',
default: 365,
},
showOverlay: {
type: 'boolean',
default: false,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Common styles for both views (editor and frontend).
.wp-block-jetpack-cookie-consent {
position: fixed;
bottom: 50px;
transition: opacity 1s ease-in-out;
animation: cookie-consent-slide-in 0.5s ease-in-out;
z-index: 50001;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
box-sizing: border-box;
align-items: center;
gap: 10px;

.wp-block-button__link {
white-space: nowrap !important;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php
/**
* Cookie-consent Block.
*
* @since $$next-version$$
*
* @package automattic/jetpack
*/

namespace Automattic\Jetpack\Extensions\CookieConsent;

use Automattic\Jetpack\Blocks;
use Jetpack_Gutenberg;

const FEATURE_NAME = 'cookie-consent';
const BLOCK_NAME = 'jetpack/' . FEATURE_NAME;
const COOKIE_NAME = 'eucookielaw';

/**
* If the site has ads, it will have its own cookie widget. This function checks if the site has ads.
*
* @since $$next-version$$
*
* @return bool
*/
function should_use_ads_cookie_widget_instead() {
return ! ( ( defined( 'NOADVERTS' )
|| defined( 'NOADSUPGRADE' )
|| 1 == get_option( 'permanent_noadverts' ) // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual,WordPress.PHP.StrictComparisons.LooseComparison -- This can be stored as string as well.
|| ( function_exists( 'has_blog_sticker' ) && has_blog_sticker( 'wordads' ) ) ) ); // Enable widget for WordAds users (regardless of plan).
}

/**
* Should the block be registered?
* We do not want to register the block when the site has ads,
* or when we're not on the frontend.
* In wp-admin, we only want to show the block in the site editor.
*
* @since $$next-version$$
*
* @return bool
*/
function should_register_block() {
return true;
global $pagenow;

if ( should_use_ads_cookie_widget_instead() ) {
return false;
}

if (
is_admin()
&& $pagenow !== 'site-editor.php'
) {
return false;
}

return true;
}

/**
* Registers the block for use in Gutenberg
* This is done via an action so that we can disable
* registration if we need to.
*/
function register_block() {
if ( ! should_register_block() ) {
return;
}

Blocks::jetpack_register_block(
BLOCK_NAME,
array( 'render_callback' => __NAMESPACE__ . '\load_assets' )
);
}
add_action( 'init', __NAMESPACE__ . '\register_block' );

/**
* Cookie-consent block registration/dependency declaration.
*
* @param array $attr Array containing the Cookie-consent block attributes.
* @param string $content String containing the Cookie-consent block content.
*
* @return string
*/
function load_assets( $attr, $content ) {
// If the user has already accepted the cookie consent, don't show the block.
if ( isset( $_COOKIE[ COOKIE_NAME ] ) ) {
return '';
}

/*
* Enqueue necessary scripts and styles.
*/
Jetpack_Gutenberg::load_assets_as_required( FEATURE_NAME );

return sprintf(
'<div class="%1$s">%2$s</div>',
esc_attr( Blocks::classes( FEATURE_NAME, $attr ) ),
$content
);
}

101 changes: 101 additions & 0 deletions projects/plugins/jetpack/extensions/blocks/cookie-consent/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { InspectorControls, useBlockProps, InnerBlocks, RichText } from '@wordpress/block-editor';
import { PanelBody, TextControl, SelectControl } from '@wordpress/components';
import { __, isRTL } from '@wordpress/i18n';
import './editor.scss';

/**
* Cookie Consent Edit Component.
*
* @param {object} props - Component props.
* @param {object} props.attributes - {object} Block attributes.
* @param {Function} props.setAttributes - Set block attributes.
* @returns {object} Element to render.
*/
function CookieConsentBlockEdit( { attributes, setAttributes } ) {
const { consentExpiryDays, align, text } = attributes;

/**
* Update the alignment of the block. This takes care setting names alignments (left, right, etc..) or eg width=500.
*
* @param {string} nextAlign - The new alignment.
*/
function updateAlignment( nextAlign ) {
const extraUpdatedAttributes = [ 'wide', 'full' ].includes( nextAlign )
? { width: undefined, height: undefined }
: {};
setAttributes( {
...extraUpdatedAttributes,
align: nextAlign,
} );
}

const { className, ...blockProps } = { ...useBlockProps() };
const classWithAlignment = className + ' align' + align;

return (
<>
<InspectorControls>
<PanelBody title={ __( 'Cookie Consent Block Settings', 'jetpack' ) }>
<SelectControl
label={ __( 'Alignment', 'jetpack' ) }
value={ align }
options={ [
{
label: isRTL() ? __( 'Right', 'jetpack' ) : __( 'Left', 'jetpack' ),
value: 'left',
},
{
label: __( 'Full', 'jetpack' ),
value: 'full',
},
{
label: __( 'Wide', 'jetpack' ),
value: 'wide',
},
{
label: isRTL() ? __( 'Left', 'jetpack' ) : __( 'Right', 'jetpack' ),
value: 'right',
},
] }
onChange={ alignValue => updateAlignment( alignValue ) }
/>
<TextControl
label={ __( 'Consent Expiry Time (in days)', 'jetpack' ) }
value={ consentExpiryDays }
type="number"
min="1"
max="365"
onChange={ value => setAttributes( { consentExpiryDays: parseInt( value ) } ) }
/>
<p>
{ __(
'Note: The block position in the editor is not indicative of the position on the front end. The block will always be positioned at the bottom of the page.',
'jetpack'
) }
</p>
</PanelBody>
</InspectorControls>
<div { ...blockProps } style={ blockProps.style } className={ classWithAlignment }>
<RichText
tagName="p"
value={ text }
onChange={ textValue => setAttributes( { text: textValue } ) }
/>
<InnerBlocks
allowedBlocks={ [ 'core/button' ] }
template={ [
[
'core/button',
{
text: __( 'Accept', 'jetpack' ),
},
],
] }
templateLock="all"
></InnerBlocks>
</div>
</>
);
}

export default CookieConsentBlockEdit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Internal dependencies
*/
import registerJetpackBlock from '../../shared/register-jetpack-block';
import { name, settings } from '.';

registerJetpackBlock( name, settings );
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Editor styles for Cookie Consent
*/

@import './common';

.wp-block-jetpack-cookie-consent {
/* Required to capture clicks */
background-color: transparent;
bottom: unset;
display: flex;
justify-content: space-between;
align-items: center;

/* when users first click the block, we don't want them to select child blocks */
&:not(.is-selected) {
* {
pointer-events: none;
}

&::before {
content: unset;
}
}

&.alignright,
&.alignleft {
max-width: 50%;
flex-wrap: nowrap;
margin-left: 0 !important;
margin-right: 0 !important;
}

&.alignright {
margin-left: auto !important;
}

&.alignwide {
width: unset;
max-width: unset;
left: unset;
}

.wp-block-button__link {
white-space: nowrap !important;
}
}
11 changes: 11 additions & 0 deletions projects/plugins/jetpack/extensions/blocks/cookie-consent/icon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* External dependencies
*/
import { SVG, Path } from '@wordpress/components';

export default (
/* @TODO Add the icon. You can use one of these https://material.io/tools/icons/?style=outline */
<SVG height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<Path d="M9 15h2V9H9v6zm1-10c-.5 0-1 .5-1 1s.5 1 1 1 1-.5 1-1-.5-1-1-1zm0-4c-5 0-9 4-9 9s4 9 9 9 9-4 9-9-4-9-9-9zm0 16c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7z" />
</SVG>
);
Loading

0 comments on commit 747eae2

Please sign in to comment.