In this tutorial, we’ll develop a dynamic Testimonial Block together. In our previous slider block tutorial, we focused on block settings (attributes). This time, we’ll be exploring the content of components to build our block.

Testimonial Slider Block Development

To create a Testimonial Slider Block, we’ll be using the Swiffy Slider library. This lightweight library is easy to implement and super user-friendly.

Before we begin, I recommend downloading and testing the plugin we’ll be building to familiarize yourself with its features and functionality.

After installing this plugin, you’ll find its icon in the editor.

With this block, users can add as many Testimonials as they want. Each Testimonial includes a paragraph to write the testimonial content, along with an image block to display a picture and the customer’s name.

The final appearance of the Testimonial Block on the front end will look like the image below.

Pre-requisites

Before following this tutorial, make sure you have the following pre-requisites.

  • Node.js and npm
  • You’ll need a local WordPress development environment set up on your machine.

Let’s dive into the code!

First, navigate to your local WordPress plugins folder and run the following command in your terminal to create the necessary files for your plugin:

npx @wordpress/create-block@latest wpcookie-testimonial --variant=dynamic

This command creates a new directory called wpcookie-testimonial. navigates into that directory and run the following command:

npm run start

This command will watch each file in the /src folder for changes. The block’s build files will be updated each time you save a file.

Understanding the Project Structure

We’ll be creating four key files that work together to build the testimonial slider block:

  1. block.json: This file defines the block’s metadata and configuration.
  2. edit.js: This file handles the block’s editing experience within the WordPress block editor.
  3. save.js: This file is responsible for rendering the block’s content on the front-end.
  4. render.php: This file generates the HTML structure for the testimonial slider on the server-side.

Let’s dive into each file and explore the code in detail.

block.json

 This file sets the stage for our block by defining its essential properties:

block.json complete code
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "create-block/wpcookie-testimonial",
	"version": "0.1.0",
	"title": "WPCookie Testimonial",
	"category": "text",
	"icon": "testimonial",
	"description": "Create testimonial slider.",
	"example": {},
	"supports": {
		"html": false

	},
	"textdomain": "wpcookie-testimonial",
	"editorScript": "file:./index.js",
	"editorStyle": "file:./index.css",
	"style": "file:./style-index.css",
	"render": "file:./render.php",
	"viewScript": ["file:./view.js", "file:./publice/swiffy-slider.min.js"]
}
  • name: Uniquely identifies the block.
  • version: Indicates the current version of the block.
  • title: Displays the block’s name in the WordPress block editor.
  • category: Categorizes the block for easier organization.
  • icon: Specifies the icon to be used for the block.
  • description: Provides a brief description of the block’s purpose.
  • supports: Defines the block’s supported features (in this case, disabling HTML support).
  • textdomain: Sets the text domain for internationalization.
  • editorScripteditorStylestyle: Specify the scripts and styles to be used for the block’s editor and front-end.
  • render: Points to the PHP file responsible for rendering the block on the server-side.
  • viewScript: Lists the JavaScript files required for the block’s front-end functionality, including the Swiffy Slider library.

index.js

Let’s go through the index.js file step-by-step.

index.js complete code
import { registerBlockType } from '@wordpress/blocks';
import './style.scss';
import Edit from './edit';
import metadata from './block.json';
import save from './save';

registerBlockType( metadata.name, {
    edit: Edit,
    save
} );

First, we’re importing the registerBlockType function from the @wordpress/blocks library. This function is used to register our custom block with WordPress.

Next, we’re importing a SCSS file called style.scss. This file contains the CSS styles that will be applied to the front-end of our block.

We’re also importing three other files:

  1. edit.js: This file contains the code that defines the editing experience of our block within the WordPress block editor.
  2. block.json: This file contains the metadata and configuration for our block, such as its name, category, and other properties.
  3. save.js: This file contains the code that defines how the block’s content should be rendered on the front-end of the website.

Finally, we’re calling the registerBlockType function and passing in two arguments:

  1. metadata.name: This is the name of our block, which was defined in the block.json file.
  2. An object with two properties:
    • edit: This is a reference to the Edit function that was imported from the edit.js file. This function defines the editing experience of our block.
    • save: This is a reference to the save function that was imported from the save.js file. This function defines how the block’s content should be rendered on the front-end.

By calling the registerBlockType function, we’re essentially telling WordPress about our custom block and providing it with the necessary information and code to make it work within the WordPress block editor and on the front-end of the website.

The index.js file is the entry point for our custom block, and it ties together all the different pieces of code (the edit.js, save.js, and block.json files) to create a complete and functional block.

This file is an important part of the custom block development process because it’s responsible for registering the block with WordPress and ensuring that all the necessary components are properly connected and integrated.

edit.js

This file defines the block’s editing experience within the WordPress block editor:

edit.js complete code
import { __} from '@wordpress/i18n';
import {
    BlockControls,
    useBlockProps,
    InnerBlocks
} from '@wordpress/block-editor';
import {
    ToolbarButton,
    ToolbarGroup,
    Button
} from '@wordpress/components';
import { createBlock} from '@wordpress/blocks';
import './editor.scss';
import personSvg from './publice/user.png'; 


export default function Edit({ }) {
    const groupOBJ ={
                className: 'testimonial-group',
                metadata: {
                    name: "testimonial"
                },
                templateLock: "insert",
                lock: {
                    move: false,
                    remove: false
                }
            };
	const columOBJ = {
				className: 'testimonial-column',
				layout: {
					type: "constrained",
					wideSize: "600px"
				},
				style: {
					spacing: {
						padding: {
							top: "30px",
							bottom: "30px",
							left: "30px",
							right: "30px"
						}
					}
					}
				};			
	const paragraphOBJ = {
				className: 'testimonial-paragraph',
				align: "center",
				placeholder: 'I have been looking for a product like this for years!'
			};
	const imageOBJ = {
				className: 'testimonial-image is-style-rounded',
				align: "center",
				scale: "cover",
				sizeSlug: "thumbnail",
				width: "55",
				height: "55",
				url: personSvg,
				caption: "Customer name"
			};
    const defaultBlocks = [
        ['core/group', groupOBJ,
            [
                ['core/column', columOBJ,
                    [
                        ['core/paragraph', paragraphOBJ ],
                        ['core/image', imageOBJ ]
                    ]
                ]
            ]
        ]
    ];
    const addGroupBlock = () => {
        const selectedBlockClientId = wp.data.select('core/block-editor').getSelectedBlockClientId();
        if (selectedBlockClientId) {
            const groupBlock = createBlock('core/group', groupOBJ, [
                createBlock('core/column', columOBJ, [
                    createBlock('core/paragraph', paragraphOBJ),
                    createBlock('core/image', imageOBJ)
                ])
            ]);
            wp.data.dispatch('core/block-editor').insertBlock(groupBlock, undefined, selectedBlockClientId);
        }
    };
    return ( 
    < > 	
			< div {...useBlockProps()} > 
				< div className = "wpcookie-testimonial-wrapper" > 
					< InnerBlocks 
						template = {defaultBlocks}
						renderAppender = {() => {return null}}
					/> 
				< /div>
			< /div> 
			< BlockControls > 
				< ToolbarGroup > 
					< Button icon = "plus-alt"
						className = "add-testimonial-btn"
						onClick = {addGroupBlock} >
						Add 
					< /Button> 
				< /ToolbarGroup> 
			< / BlockControls > 
        < />);
}

First, we’re importing some necessary functions and components from the WordPress libraries. These allow us to create and customize the block within the WordPress block editor.

  • __ is a function from the @wordpress/i18n library that helps with internationalization and translation.
  • BlockControlsuseBlockProps, and InnerBlocks are components from the @wordpress/block-editor library, which provide tools for building and managing the block’s structure and appearance.
  • ToolbarButtonToolbarGroup, and Button are components from the @wordpress/components library, which give us pre-built UI elements to use in our block.
  • createBlock is a function from the @wordpress/blocks library, which allows us to programmatically create new blocks.
  • We’re also importing a custom SCSS file (editor.scss) and an image file (personSvg) that we’ll use in the block.
export default function Edit({ }) {
    // Define the structure and styles for the block
    const groupOBJ = {
        className: 'testimonial-group',
        metadata: {
            name: "testimonial"
        },
        templateLock: "insert",
        lock: {
            move: false,
            remove: false
        }
    };
    const columOBJ = {
        className: 'testimonial-column',
        layout: {
            type: "constrained",
            wideSize: "600px"
        },
        style: {
            spacing: {
                padding: {
                    top: "30px",
                    bottom: "30px",
                    left: "30px",
                    right: "30px"
                }
            }
        }
    };
    const paragraphOBJ = {
        className: 'testimonial-paragraph',
        align: "center",
        placeholder: 'I have been looking for a product like this for years!'
    };
    const imageOBJ = {
        className: 'testimonial-image is-style-rounded',
        align: "center",
        scale: "cover",
        sizeSlug: "thumbnail",
        width: "55",
        height: "55",
        url: personSvg,
        caption: "Customer name"
    };

Next, we’re defining the structure and styles for the different elements of the testimonial block. We’re creating four objects:

  1. groupOBJ: This sets the class name, metadata, and lock settings for the overall “testimonial-group” block.
  2. columOBJ: This sets the class name, layout, and padding styles for the “testimonial-column” block.
  3. paragraphOBJ: This sets the class name, alignment, and placeholder text for the “testimonial-paragraph” block.
  4. imageOBJ: This sets the class name, alignment, size, and image details for the “testimonial-image” block.

These objects will be used to define the default structure and appearance of the testimonial block.

const defaultBlocks = [
        ['core/group', groupOBJ, [
            ['core/column', columOBJ, [
                ['core/paragraph', paragraphOBJ],
                ['core/image', imageOBJ]
            ]]
        ]]
    ];

The defaultBlocks array defines the initial content of the testimonial block. It includes a “core/group” block with the settings from the groupOBJ, which contains a “core/column” block with the settings from the columOBJ. Inside the column, there’s a “core/paragraph” block with the settings from the paragraphOBJ and a “core/image” block with the settings from the imageOBJ.

const addGroupBlock = () => {
        const selectedBlockClientId = wp.data.select('core/block-editor').getSelectedBlockClientId();
        if (selectedBlockClientId) {
            const groupBlock = createBlock('core/group', groupOBJ, [
                createBlock('core/column', columOBJ, [
                    createBlock('core/paragraph', paragraphOBJ),
                    createBlock('core/image', imageOBJ)
                ])
            ]);
            wp.data.dispatch('core/block-editor').insertBlock(groupBlock, undefined, selectedBlockClientId);
        }
    };

The addGroupBlock function is responsible for adding a new “testimonial-group” block when the user clicks the “Add” button in the block controls. It first gets the ID of the currently selected block, then creates a new “core/group” block with the settings from the groupOBJ, and a “core/column” block with the settings from the columOBJ (containing a “core/paragraph” and a “core/image” block). Finally, it inserts the new block group at the position of the currently selected block.

return (
        <>
            <div { ...useBlockProps() }>
                <div className="wpcookie-testimonial-wrapper">
                    <InnerBlocks
                        template={defaultBlocks}
                        renderAppender={() => { return null }}
                    />
                </div>
            </div>
            <BlockControls>
                <ToolbarGroup>
                    <Button icon="plus-alt"
                        className="add-testimonial-btn"
                        onClick={addGroupBlock}>
                        Add
                    </Button>
                </ToolbarGroup>
            </BlockControls>
        </>
    );
}

Finally, the return statement defines the structure of the block’s editing experience. It includes:

  1. <div> with the useBlockProps() settings, which contains the “wpcookie-testimonial-wrapper” class and an <InnerBlocks> component that renders the defaultBlocks structure.
  2. <BlockControls> component that includes a <ToolbarGroup> with a <Button> that calls the addGroupBlock function when clicked, allowing the user to add a new testimonial group.

By putting all these pieces together, you’ve created a custom testimonial block that can be easily added and customized within the WordPress block editor.

save.js

let’s go through the save.js file step-by-step.

save.js complete code
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';

export default function save( ) {

    return (
        <div { ...useBlockProps.save() }>			
				<InnerBlocks.Content />
        </div>
    );
}

First, we’re importing two functions from the @wordpress/block-editor library: InnerBlocks and useBlockProps. These functions ensures that the testimonial slider block’s content and styling are saved and displayed correctly on the front end of your website.

export default function save() {

This is the main function of the save.js file, which is responsible for saving the block’s content on the front-end. The name of the function is save, and it’s the default export from this file.

export default function save() {

Inside the save function, we’re returning some HTML code that will be rendered on the front-end of the website.

The <div> element has a special attribute: { ...useBlockProps.save() }. This is a way to apply the necessary styles and attributes to the block’s container, so that it looks and behaves correctly on the front-end.

Inside the <div>, we have the <InnerBlocks.Content /> component. This component is responsible for rendering the actual content of the block, which was defined in the edit.js file.

So, in a nutshell, the save.js file is responsible for taking the content and styles defined in the block’s editing experience (the edit.js file) and saving them correctly on the database of the website.

render.php

let’s go through the render.php file step-by-step

render.php complete code
<?php

$htmlContent = $content;
$dom = new DOMDocument();
$dom->loadHTML($htmlContent);
$xpath = new DOMXPath($dom);
$query = '//div[contains(@class, \'testimonial-group\')]';
$divs = $xpath->query($query);
$testimonialGroup = [];

// Loop through the divs and save their content to the array
foreach ($divs as $div) {
    $testimonialGroup[] = $dom->saveHTML($div);
} 
?>

<div class="swiffy-slider slider-nav-dark slider-nav-sm slider-nav-visible slider-nav-touch slider-indicators-round slider-indicators-dark slider-indicators-sm slider-nav-animation">
	<ul class="slider-container" >		
		<?php
		foreach ($testimonialGroup as $value) {
			$key++;
			echo '<li >'.$value.'</li>';
		} ?>       
	</ul>
	<button type="button" class="slider-nav"></button>
    <button type="button" class="slider-nav slider-nav-next"></button>	
    <ul class="slider-indicators">
		<?php
		foreach ($testimonialGroup as $value) {
			echo '<li></li>';
		} ?>
        
    </ul>
	
</div>	
<?php
$htmlContent = $content;
$dom = new DOMDocument();
$dom->loadHTML($htmlContent);
$xpath = new DOMXPath($dom);
$query = '//div[contains(@class, \'testimonial-group\')]';
$divs = $xpath->query($query);
$testimonialGroup = [];

First, we’re taking the content of the block (stored in the $content variable) and storing it in the $htmlContent variable.

Then, we’re creating a new DOMDocument object, which is a way to work with HTML and XML documents in PHP. We’re loading the $htmlContent into this DOMDocument object.

Next, we’re creating a new DOMXPath object, which is a tool that helps us search and extract specific elements from the DOMDocument.

We’re using the $xpath object to find all the <div> elements that have a class name containing the text “testimonial-group”. This query is stored in the $query variable.

Finally, we’re executing the $query and storing the resulting <div> elements in the $divs variable. We’re also creating an empty array called $testimonialGroup, which we’ll use to store the HTML content of these <div> elements.

foreach ($divs as $div) {
    $testimonialGroup[] = $dom->saveHTML($div);
}

Now, we’re looping through the $divs array (which contains the <div> elements with the “testimonial-group” class). For each <div> element, we’re using the $dom->saveHTML() function to save the HTML content of that <div> and adding it to the $testimonialGroup array.

?>

<div class="swiffy-slider slider-nav-dark slider-nav-sm slider-nav-visible slider-nav-touch slider-indicators-round slider-indicators-dark slider-indicators-sm slider-nav-animation">
    <ul class="slider-container">
        <?php
        foreach ($testimonialGroup as $value) {
            $key++;
            echo '<li >' . $value . '</li>';
        }
        ?>
    </ul>
    <button type="button" class="slider-nav"></button>
    <button type="button" class="slider-nav slider-nav-next"></button>
    <ul class="slider-indicators">
        <?php
        foreach ($testimonialGroup as $value) {
            echo '<li></li>';
        }
        ?>
    </ul>
</div>

In this last part, we’re creating the HTML structure for the testimonial slider. We’re using a <div> with the class “swiffy-slider” to create the slider container.

Inside the slider container, we have:

  1. An unordered list (<ul>) with the class “slider-container”, which will hold the individual testimonial slides.
  2. Two buttons with the class “slider-nav” to allow the user to navigate the slider.
  3. Another unordered list (<ul>) with the class “slider-indicators”, which will display the pagination dots for the slider.

We’re then using a foreach loop to iterate through the $testimonialGroup array, which contains the HTML content of the “testimonial-group” <div> elements. For each item in the array, we’re:

  1. Embedding the HTML content inside a <li> element, which will be a slide in the slider.
  2. Adding an empty <li> element to the “slider-indicators” list.

This way, the testimonial slider will display the content of the “testimonial-group” <div> elements, and the pagination dots will correspond to each testimonial slide.

Adding JavaScript and CSS files

Adding JavaScript File

In the src folder, create a new folder called publice and copy the swiffy-slider.min.js file into it. We have already introduced this file in block.json as a part of the viewScript property:

"viewScript": [
    "file:./view.js",
    "file:./publice/swiffy-slider.min.js"
]

This ensures that the swiffy-slider.min.js file will be loaded on the front-end when the block is rendered.

As a placeholder for the customer’s image, copy the user.png file to the “public” folder. If you look at the edit.js file, you’ll notice that we have already imported this image there. This placeholder ensures that you have a preview of how the testimonial slider block will look with a customer’s image in place while you’re editing the block.

user.png

Adding CSS Styles

In the style.scss file, we need to include the styles provided by the Swiffy Slider library. You can paste the contents of the swiffy-slider.min.css file at the end of style.scss file, after our own style.

style.scss complete code
div.testimonial-group {
	img {width: 55px; margin: auto;}
	figcaption { width: 250px;}
}

button.slider-nav:hover, button.slider-nav:focus {
    background: #ffffff00;
    box-shadow: none;
}
.swiffy-slider{
	max-width: 650px!important;
	direction: ltr;
}


.swiffy-slider{position:relative;display:block;width:100%;--swiffy-slider-snap-align:center;--swiffy-slider-item-width:100%;--swiffy-slider-item-gap:1rem;--swiffy-slider-item-reveal:0rem;--swiffy-slider-item-ratio:2/1;--swiffy-slider-item-count:1;--swiffy-slider-nav-light:#fff;--swiffy-slider-nav-dark:#333;--swiffy-slider-nav-zoom:1;--swiffy-slider-track-opacity:0.1;--swiffy-slider-track-height:0;--swiffy-slider-nav-outside-size:3.5rem;--swiffy-slider-indicator-outside-size:1.5rem;--swiffy-slider-animation-duration:.75s;--swiffy-slider-animation-delay:0s;--swiffy-slider-animation-timing:ease-in-out}.swiffy-slider,.swiffy-slider::after,.swiffy-slider::before{box-sizing:border-box}.swiffy-slider ::-webkit-scrollbar{height:var(--swiffy-slider-track-height)}.swiffy-slider ::-webkit-scrollbar-track{background:rgba(0,0,0,var(--swiffy-slider-track-opacity))}.swiffy-slider ::-webkit-scrollbar-thumb{background:rgba(0,0,0,.4);border-radius:1rem}.swiffy-slider ::-webkit-scrollbar-thumb:hover{background:rgba(0,0,0,.6)}.slider-container{--swiffy-slider-item-gap-totalwidth:calc(var(--swiffy-slider-item-gap) * (var(--swiffy-slider-item-count) - 1));--swiffy-slider-item-width:calc((100% - var(--swiffy-slider-item-reveal) - var(--swiffy-slider-item-gap-totalwidth)) / var(--swiffy-slider-item-count));overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-scroll-snap-type:x mandatory;scroll-snap-type:x mandatory;scroll-behavior:smooth;display:grid;align-items:center;height:100%;grid:auto/auto-flow -webkit-max-content;grid:auto/auto-flow max-content;grid-auto-rows:100%;grid-auto-columns:var(--swiffy-slider-item-width);grid-auto-flow:column;grid-gap:var(--swiffy-slider-item-gap);list-style:none;margin:0;padding:0;scrollbar-width:none;scrollbar-color:rgba(0,0,0,.4) rgba(0,0,0,var(--swiffy-slider-track-opacity));background-clip:padding-box}.slider-container>*{scroll-snap-align:var(--swiffy-slider-snap-align);position:relative;width:100%;height:100%}.slider-item-helper .slider-container>*{background-size:cover;background-color:#e1e1e1;background-position:50% 50%;display:flex;justify-content:center;align-items:center}.slider-item-helper:not(.slider-item-ratio) .slider-container>*{min-height:20rem}.slider-item-ratio .slider-container>*>*{position:absolute;top:0;left:0;width:100%;height:100%;-o-object-fit:cover;object-fit:cover}.slider-item-ratio-contain .slider-container>*>*{-o-object-fit:contain;object-fit:contain}.slider-item-ratio .slider-container>::after{display:block;padding-top:calc(100% / (var(--swiffy-slider-item-ratio)));content:""}.slider-item-ratio-32x9{--swiffy-slider-item-ratio:32/9}.slider-item-ratio-21x9{--swiffy-slider-item-ratio:21/9}.slider-item-ratio-16x9{--swiffy-slider-item-ratio:16/9}.slider-item-ratio-4x3{--swiffy-slider-item-ratio:4/3}.slider-item-ratio-2x1{--swiffy-slider-item-ratio:2/1}.slider-item-ratio-1x1{--swiffy-slider-item-ratio:1/1}.slider-item-ratio-3x4{--swiffy-slider-item-ratio:3/4}.slider-nav-scrollbar{--swiffy-slider-track-height:0.5rem}.slider-nav-scrollbar .slider-container{scrollbar-width:thin}.slider-nav-nodelay .slider-container{scroll-behavior:auto}.slider-indicators{position:absolute;right:2rem;bottom:0;left:2rem;display:flex;justify-content:center;padding:0;margin-bottom:1rem;list-style:none}.slider-nav-scrollbar .slider-indicators{margin-bottom:calc(1rem + var(--swiffy-slider-track-height))}.slider-indicators>.active{opacity:1}.swiffy-slider.slider-indicators-outside .slider-nav{margin-bottom:var(--swiffy-slider-indicator-outside-size)}.swiffy-slider.slider-indicators-outside{padding-bottom:var(--swiffy-slider-indicator-outside-size)}.swiffy-slider.slider-indicators-outside .slider-indicators,.swiffy-slider.slider-indicators-outside.slider-indicators{margin-bottom:0}.slider-indicators>*{box-sizing:content-box;flex:0 1 auto;width:2rem;height:.2rem;padding:0;border:.4rem solid transparent;cursor:pointer;background-color:#fff;background-clip:padding-box;opacity:.5;transition:opacity .4s ease}.slider-indicators-square .slider-indicators>*,.slider-indicators-square.slider-indicators>*{width:.5rem;height:.5rem;border:.4rem solid transparent}.slider-indicators-round .slider-indicators>*,.slider-indicators-round.slider-indicators>*{width:.5rem;height:.5rem;border:.4rem solid transparent;border-radius:50%}.slider-indicators-highlight .slider-indicators>.active,.slider-indicators-highlight.slider-indicators>.active{border:.33rem solid transparent;padding:.07rem}.slider-nav{position:absolute;top:0;left:0;bottom:0;border:0;background-color:transparent;cursor:pointer;padding:0;visibility:hidden;opacity:.8;transition:visibility .1s,opacity .2s linear;margin-bottom:var(--swiffy-slider-track-height);display:flex;align-items:center;padding:0 .5rem;-webkit-filter:drop-shadow(0 0 .5rem rgba(0, 0, 0, .5));filter:drop-shadow(0 0 .5rem rgba(0, 0, 0, .5));transform:scale(var(--swiffy-slider-nav-zoom))}.slider-nav::before{position:absolute;content:"";padding:.5rem;width:3rem;height:3rem}.slider-nav::after{content:"";-webkit-mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'><path fill-rule='evenodd' d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'></path></svg>");mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'><path fill-rule='evenodd' d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'></path></svg>");-webkit-mask-size:cover;mask-size:cover;background-color:var(--swiffy-slider-nav-light);background-origin:content-box;width:3rem;height:3rem}.slider-nav-arrow .slider-nav::after{-webkit-mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'><path fill-rule='evenodd' d='M12 8a.5.5 0 0 1-.5.5H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H11.5a.5.5 0 0 1 .5.5z'></path></svg>");mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'><path fill-rule='evenodd' d='M12 8a.5.5 0 0 1-.5.5H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H11.5a.5.5 0 0 1 .5.5z'></path></svg>")}.slider-nav-chevron .slider-nav::after{-webkit-mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'><path fill-rule='evenodd' d='M9.224 1.553a.5.5 0 0 1 .223.67L6.56 8l2.888 5.776a.5.5 0 1 1-.894.448l-3-6a.5.5 0 0 1 0-.448l3-6a.5.5 0 0 1 .67-.223z'></path></svg>");mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'><path fill-rule='evenodd' d='M9.224 1.553a.5.5 0 0 1 .223.67L6.56 8l2.888 5.776a.5.5 0 1 1-.894.448l-3-6a.5.5 0 0 1 0-.448l3-6a.5.5 0 0 1 .67-.223z'></path></svg>")}.slider-nav-caret .slider-nav::after{-webkit-mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'><path d='M10 12.796V3.204L4.519 8 10 12.796zm-.659.753-5.48-4.796a1 1 0 0 1 0-1.506l5.48-4.796A1 1 0 0 1 11 3.204v9.592a1 1 0 0 1-1.659.753z'></path></svg>");mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'><path d='M10 12.796V3.204L4.519 8 10 12.796zm-.659.753-5.48-4.796a1 1 0 0 1 0-1.506l5.48-4.796A1 1 0 0 1 11 3.204v9.592a1 1 0 0 1-1.659.753z'></path></svg>")}.slider-nav-caretfill .slider-nav::after{-webkit-mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'><path d='m3.86 8.753 5.482 4.796c.646.566 1.658.106 1.658-.753V3.204a1 1 0 0 0-1.659-.753l-5.48 4.796a1 1 0 0 0 0 1.506z'></path></svg>");mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'><path d='m3.86 8.753 5.482 4.796c.646.566 1.658.106 1.658-.753V3.204a1 1 0 0 0-1.659-.753l-5.48 4.796a1 1 0 0 0 0 1.506z'></path></svg>")}.swiffy-slider:hover .slider-nav{visibility:visible}.swiffy-slider.slider-nav-autohide.slider-item-first-visible .slider-nav:not(.slider-nav-next){visibility:hidden}.swiffy-slider.slider-nav-autohide.slider-item-last-visible .slider-nav.slider-nav-next{visibility:hidden}.slider-nav-outside .slider-container{margin:0 var(--swiffy-slider-nav-outside-size)}.slider-nav-outside .slider-nav{padding:0}.swiffy-slider .slider-nav:hover{opacity:1}.slider-nav-square .slider-nav{padding:0}.slider-nav-round .slider-nav::before,.slider-nav-square .slider-nav::before{background-color:var(--swiffy-slider-nav-light)}.slider-nav-round .slider-nav::after,.slider-nav-square .slider-nav::after{background-color:var(--swiffy-slider-nav-dark);width:2rem;height:2rem;margin:.5rem}.slider-nav-round .slider-nav::before{border-radius:50%}.slider-nav-round .slider-nav::after{-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' %3E%3Cpath fill-rule='evenodd' d='M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z'%3E%3C/path%3E%3C/svg%3E");mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' %3E%3Cpath fill-rule='evenodd' d='M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z'%3E%3C/path%3E%3C/svg%3E")}.slider-nav-dark .slider-nav::after{background-color:var(--swiffy-slider-nav-dark)}.slider-nav-dark.slider-nav-round .slider-nav::before,.slider-nav-dark.slider-nav-square .slider-nav::before{background-color:var(--swiffy-slider-nav-dark)}.slider-nav-dark.slider-nav-round .slider-nav::after,.slider-nav-dark.slider-nav-square .slider-nav::after{background-color:var(--swiffy-slider-nav-light)}.slider-nav-sm{--swiffy-slider-nav-zoom:.75;--swiffy-slider-nav-outside-size:2.5rem}.slider-nav.slider-nav-next::after{transform:rotate(180deg)}.slider-nav.slider-nav-next{right:0;left:unset}.slider-nav-visible .slider-nav{visibility:visible}.slider-nav-dark .slider-nav{opacity:.6}.slider-indicators-dark .slider-indicators>*,.slider-indicators-dark.slider-indicators>*{-webkit-filter:invert(1);filter:invert(1)}.slider-item-snapstart{--swiffy-slider-snap-align:start}.slider-item-nosnap{--swiffy-slider-snap-align:unset}.slider-item-nogap{--swiffy-slider-item-gap:0rem}.slider-item-reveal{--swiffy-slider-item-reveal:8rem}.slider-item-snapstart.slider-item-reveal{--swiffy-slider-item-reveal:4rem}.slider-item-show2{--swiffy-slider-item-count:2}.slider-item-show3{--swiffy-slider-item-count:3}.slider-item-show4{--swiffy-slider-item-count:4}.slider-item-show5{--swiffy-slider-item-count:5}.slider-item-show6{--swiffy-slider-item-count:6}.slider-nav-mousedrag .slider-container{cursor:-webkit-grab;cursor:grab}.slider-nav-mousedrag.dragging .slider-container{-ms-scroll-snap-type:unset;scroll-snap-type:unset;scroll-behavior:unset;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.slider-nav-mousedrag.dragging .slider-nav{visibility:hidden}@media (hover:hover){.slider-nav-mousedrag .slider-container::after{content:"";position:absolute;width:100%;height:100%}}@media (prefers-reduced-motion:no-preference){.slider-nav-animation.slider-nav-animation-fast{--swiffy-slider-animation-duration:.25s}.slider-nav-animation.slider-nav-animation-slow{--swiffy-slider-animation-duration:1.25s}.slider-nav-animation .slider-container>*>*{transition:opacity var(--swiffy-slider-animation-duration) var(--swiffy-slider-animation-timing),transform var(--swiffy-slider-animation-duration) var(--swiffy-slider-animation-timing);transition-delay:var(--swiffy-slider-animation-delay)}.slider-nav-animation .slider-container .slide-visible>*{transition:opacity var(--swiffy-slider-animation-duration) var(--swiffy-slider-animation-timing),transform var(--swiffy-slider-animation-duration) var(--swiffy-slider-animation-timing);transition-delay:var(--swiffy-slider-animation-delay)}.slider-nav-animation.slider-nav-animation-fadein .slider-container>*>*{opacity:.5}.slider-nav-animation.slider-nav-animation-scale .slider-container>*>*{transform:scale(.9)}.slider-nav-animation.slider-nav-animation-appear .slider-container>*>*{opacity:.3;transform:scale(.9)}.slider-nav-animation.slider-nav-animation-scaleup .slider-container>*>*{transform:scale(.25)}.slider-nav-animation.slider-nav-animation-zoomout .slider-container>*{overflow:hidden}.slider-nav-animation.slider-nav-animation-zoomout .slider-container>*>*{transform:scale(1.3)}.slider-nav-animation.slider-nav-animation-turn .slider-container>*>*{transform:rotateY(70deg)}.slider-nav-animation.slider-nav-animation-slideup .slider-container>*>*{transform:translateY(60%) scale(.99)}.slider-nav-animation.slider-nav-animation-slideup .slider-container{overflow-y:hidden}.slider-nav-animation .slider-container>.slide-visible>*{opacity:1;transform:none}}@media (min-width:62rem){.slider-item-show2:not(.slider-item-snapstart) .slider-container>*,.slider-item-show4:not(.slider-item-snapstart) .slider-container>*,.slider-item-show6:not(.slider-item-snapstart) .slider-container>*{scroll-snap-align:unset}.slider-item-show2:not(.slider-item-snapstart) .slider-container>::before,.slider-item-show4:not(.slider-item-snapstart) .slider-container>::before,.slider-item-show6:not(.slider-item-snapstart) .slider-container>::before{content:" ";display:block;position:absolute;left:calc((var(--swiffy-slider-item-gap)/2)*-1);top:0;width:1px;height:1px;scroll-snap-align:var(--swiffy-slider-snap-align)}.slider-nav-outside-expand .slider-nav{margin-left:-4rem}.slider-nav-outside-expand .slider-nav.slider-nav-next{margin-right:-4rem}.slider-nav-sm.slider-nav-outside-expand .slider-nav{margin-left:-3.5rem}.slider-nav-sm.slider-nav-outside-expand .slider-nav.slider-nav-next{margin-right:-3.5rem}.slider-indicators-sm.slider-indicators{display:none}}@media (max-width:62rem){.swiffy-slider{--swiffy-slider-track-height:0rem;--swiffy-slider-item-reveal:0rem;--swiffy-slider-item-count:1;--swiffy-slider-nav-zoom:.875}.swiffy-slider .slider-item-show2-sm{--swiffy-slider-item-count:2}.slider-item-reveal{--swiffy-slider-item-reveal:4rem}.slider-item-snapstart.slider-item-reveal{--swiffy-slider-item-reveal:2rem}.slider-item-show6 .slider-container{grid-auto-columns:calc(25% - (var(--swiffy-slider-item-gap)/ 4*3))}.slider-item-show6.slider-item-reveal .slider-container{grid-auto-columns:calc(25% - (var(--swiffy-slider-item-gap)/ 4*3) - .5rem)}.slider-item-show6.slider-item-reveal .slider-container>*{scroll-snap-align:unset}.slider-item-show6.slider-item-reveal .slider-container>::before{content:" ";display:block;position:absolute;left:calc((var(--swiffy-slider-item-gap)/2)*-1);top:0;width:1px;height:1px;scroll-snap-align:center}.slider-nav::after,.slider-nav::before{width:2rem;height:2rem;padding:.3rem}.slider-nav-round .slider-nav::after,.slider-nav-square .slider-nav::after{width:1.75rem;height:1.75rem;margin:.125rem}.slider-nav-outside .slider-container,.slider-nav-outside-expand .slider-container{margin:0 2rem}.slider-nav-outside-expand .slider-container{margin:0 var(--swiffy-slider-nav-outside-size)}.slider-nav-outside-expand .slider-nav{padding:0}.slider-indicators-round .slider-indicators>*,.slider-indicators-round.slider-indicators>*,.slider-indicators-square .slider-indicators>*,.slider-indicators-square.slider-indicators>*{width:.3rem;height:.3rem}.slider-indicators{margin-bottom:.5rem;display:none}.slider-nav-scrollbar .slider-indicators{margin-bottom:0}.slider-indicators>*{width:1rem;height:.125rem;border-width:.25rem}.slider-indicators-sm .slider-indicators,.slider-indicators-sm.slider-indicators{display:flex}}@media (max-width:48rem){.slider-item-show6 .slider-container{grid-auto-columns:calc(50% - (var(--swiffy-slider-item-gap)/ 2))}.slider-item-show6.slider-item-reveal .slider-container{grid-auto-columns:calc(50% - (var(--swiffy-slider-item-gap)/ 2) - 1.5rem)}}@media (hover:none){.swiffy-slider.slider-nav-touch .slider-nav{visibility:visible}.swiffy-slider:not(.slider-nav-touch).slider-nav-outside .slider-container,.swiffy-slider:not(.slider-nav-touch).slider-nav-outside-expand .slider-container{margin:0 0}.slider-item-nosnap-touch{--swiffy-slider-snap-align:unset}}
/*# sourceMappingURL=swiffy-slider.min.css.map */

In the editor.scss file, we’ll write the styles specifically related to the block editor.

editor.scss complete code
.wpcookie-testimonial-wrapper > div > div {
    display: flex;
    flex-direction: row;
    gap: 5px;
    overflow-x: scroll;
}
.wpcookie-testimonial-wrapper figure {
    display: flex!important;
    flex-direction: column!important;
    align-content: center!important;
    align-items: center!important;
}
.wpcookie-testimonial-wrapper figcaption {
    width: 200px!important;
}
div.my-custom-group {
    max-width: 600px;
}

If this article is difficult for you to read in text, you can watch the video version below.

Share this post
Maya
Maya

Hi, my name is Maya and I’m a WordPress plugin developer. I created this website to share some of the helpful codes that I’ve used in my own projects.
If you’re looking for a custom plugin for your website, you can contact me by clicking on Hire a developer in the menu. I’d love to hear from you.

Articles: 57

2 Comments

  1. Hi, this code seems to be completely wrong? It\’s also very different from the code in the plugin available for download. Has it not been updated recently?

    • Hi Eli, thank you for your comment!

      The code in the post is part of the development process and includes files like block.json, index.js, edit.js, save.js, and render.php. To get the final plugin, you’ll need to build the block using @wordpress/create-block or a similar setup in your development environment (e.g., VS Code with Node.js). Once you run the build process, it compiles the code into the format you see in the downloadable plugin.

Leave a Reply

Your email address will not be published. Required fields are marked *