Building a Custom Slider Block in 30 minutes with ACF

https://www.loom.com/embed/6e357b8d23324450bf642e7b8bba507e

Theme setup

Create a folder and files for your custom block:

- templates
  - blocks
    - slider
      - slider.js
      - slider.php
      - slider.scss

Documentation and Examples

https://www.advancedcustomfields.com/resources/blocks/

https://www.advancedcustomfields.com/resources/acf_register_block_type/

Register a block

  • Note: all the code assumes a Sage 8 theme (that is what I use)

Grab the code from the  acf_register_block_type page, and adapt it for our slider (and the Sage theme)

add_action('acf/init', __NAMESPACE__ .'\\my_register_blocks');
function my_register_blocks() {

    // check function exists.
    if( function_exists('acf_register_block_type') ) {

        // Register a testimonial block.
        acf_register_block_type(array(
            'name'              => 'slider',
            'title'             => __('Slider'),
            'description'       => __('A custom slider block.'),
            'render_template'   => get_template_directory() . '/templates/blocks/slider/slider.php',
            'category'          => 'formatting',
            'icon'              => 'images-alt2',
        ));
    }
}

Enqueue block assets.

We will use the following jquery slider for our slider block:

https://kenwheeler.github.io/slick/

We will have to enqueue the dependencies for this slider using enqueue_assets

Again: copy the code from the  acf_register_block_type page. We are using the callback function enqueue_assets, and we add it to our block registration code.

Note: The great thing about using the callback function is that it only will be called when it is necessary, so only if the block is used.

Also use the CDN links from the Slick github page to enqueue the Slick assets

add_action('acf/init', __NAMESPACE__ .'\\my_register_blocks');
function my_register_blocks() {

    // check function exists.
    if( function_exists('acf_register_block_type') ) {

        // Register a testimonial block.
        acf_register_block_type(array(
            'name'              => 'slider',
            'title'             => __('Slider'),
            'description'       => __('A custom slider block.'),
            'render_template'   => get_template_directory() . '/templates/blocks/slider/slider.php',
            'category'          => 'formatting',
            'icon'              => 'images-alt2',
            'enqueue_assets' => function(){
              wp_enqueue_style( 'slick', 'http://cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.css', array(), '1.8.1' );
              wp_enqueue_style( 'slick-theme', 'http://cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick-theme.css', array(), '1.8.1' );
              wp_enqueue_script( 'slick', 'http://cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js', array('jquery'), '1.8.1', true);

//wp_enqueue_style( 'block-slider', get_template_directory_uri() . '/templates/blocks/slider/slider.min.scss', array(), '1.0.0' );

//wp_enqueue_script( 'block-slider', get_template_directory_uri() . '/templates/blocks/slider/slider.min.js', array('jquery'), '1.0.0', true );
            }
        ));
    }
}

I replaced the last 2 lines with the code below, because I placed my assets for the block in the Assets folder of Sage 8

wp_enqueue_script( 'blocks', get_template_directory_uri() . '/assets/scripts/blocks/slider.js', array('slick'), '1.0.0', true );

The asset are placed like this:

Assets
  scripts
    blocks
      slider.js
  styles
    blocks
      _slider.scss

The slider.js file is added to blocks.js in manifest.json

"dependencies": {
    "main.js": {
      "files": [
        "scripts/main.js"
      ],
      "main": true
    },
    "blocks.js": {
      "files": [
        "scripts/blocks/slider.js"
      ]
    },

And blocks is enqueued (with slick as dependency) as already shown

The _slider.scss file is simply imported in main.scss like the other scss files

The block should now be visible in the WP editor, (although it does nothing yet)

Create fields

Let’s create a very simple repeater image field for the slider:

As the location you should now be able to select the ‘slides’ block:

Create block HTML

Grab the example template from the  acf_register_block_type page and paste it in your slider.php file and adapt it to your slider block

<?php

/**
 * Slider Block Template.
 *
 * @param   array $block The block settings and attributes.
 * @param   string $content The block inner HTML (empty).
 * @param   bool $is_preview True during AJAX preview.
 * @param   (int|string) $post_id The post ID this block is saved to.
 */

// Create id attribute allowing for custom "anchor" value.
$id = 'slider' . $block['id'];
if( !empty($block['anchor']) ) {
    $id = $block['anchor'];
}

// Create class attribute allowing for custom "className" and "align" values.
$className = 'slider';
if( !empty($block['className']) ) {
    $className .= ' ' . $block['className'];
}
if( !empty($block['align']) ) {
    $className .= ' align' . $block['align'];
}

?>
<div id="<?php echo esc_attr($id); ?>" class="<?php echo esc_attr($className); ?>">
    <?php if( have_rows('slides') ): ?>
        <div class="slides">
            <?php while( have_rows('slides') ): the_row();
                $image = get_sub_field('image');
                ?>
                <div>
                    <?php echo wp_get_attachment_image( $image['id'], 'full' );?>
                </div>
            <?php endwhile; ?>
        </div>
    <?php else: ?>
        <!-- Necessary, to make sure there is something when the block is still empty in admin -->
        <p>Please add some slides</p>
    <?php endif; ?>
</div>

You should now see this when you add a slider block to a page:

And in the sidebar you should be able to add slides to this block

Create block JavaScript.

Grab the example template (testimonial.js) for js at the  acf_register_block_type page and paste it in your slider.js file and adapt it.

For this example we use the js code for the ‘Variable Width’ slider on the Slick page:

$(‘.variable-width’).slick({
dots: true,
infinite: true,
speed: 300,
slidesToShow: 1,
centerMode: true,
variableWidth: true
});

And put that in the initializeBlock function

Note: we need to change the global selector, because we should only target the slider of this particular block instance. We can do it like this (.slides is the div that wraps the individual slide divs).

$block.find(‘.slides’).slick({

Of course you can add/change other slick options if you want

The slider should now work!

Styling the block

You can now make some changes to the styles of the slider if you want.

NOTE: ideally all styles that are added to the frontend stylesheet are applied to the backend style as well. At the time of writing the frontend styles are not applied to the gutenberg blocks for some reason (Sage 8).
See the solution under ‘Admin problems’ to apply styles ot the backend anyway.

Fix admin problems

Fix selectable issue

You may notice that it is difficult to select the slider block in WordPress admin. You can not click anywhere to select it because the slick js is interfering with the admin js.

To fix this we can make use of the variable $is_preview that we can see in the Block template

$is_preview is true when you are in the backend

So we can apply a class to the block only when $is_preview is True.

Add this to the block template:

if( $is_preview ){
$className .= ‘ is-preview’;
}

Result in the backend:

Now add the following style to the stylesheet of the block:

.slider.is-preview:before {
  content: '';
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  /*background: red;*/ 
  z-index: 1;
}

NOTE: ideally this should be added to the normal stylesheet that is used for the frontend. At the time of writing the frontend styles are not applied to the gutenberg blocks for some reason (Sage 8).

So I have a separate blocks.css in the theme root folder, which is enqueued as follows:

/**
 * Enqueue Gutenberg scripts and styles to backend area.
 */
function my_gutenberg_assets() {
  wp_enqueue_style( 'my-gutenberg-admin', get_stylesheet_directory_uri() . '/blocks.css', array(), '1.0.0' );
}
add_action( 'enqueue_block_assets', __NAMESPACE__ . '\\my_gutenberg_assets' );

This overlays an invisible element over the block so that clicks won’t cause problems anymore.

Another problem: when adding a block below the slider, the + overlaps the controls of the slider:

To fix this we will add margin below the slider block

.slider.is-preview {
margin-bottom: 70px;
}

Result: