{"id":11354,"date":"2019-07-14T16:46:32","date_gmt":"2019-07-14T14:46:32","guid":{"rendered":"https:\/\/hesmid.nl\/test\/?p=11354"},"modified":"2019-07-20T09:27:14","modified_gmt":"2019-07-20T07:27:14","slug":"building-a-custom-slider-block-in-30-minutes-with-acf","status":"publish","type":"post","link":"https:\/\/hesmid.nl\/test\/building-a-custom-slider-block-in-30-minutes-with-acf\/","title":{"rendered":"Building a Custom Slider Block in 30 minutes with ACF"},"content":{"rendered":"\n<figure class=\"wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-acf\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"BxyS0AP3Rt\"><a href=\"https:\/\/www.advancedcustomfields.com\/blog\/building-a-custom-slider-block-in-30-minutes-with-acf\/\">Building a Custom Slider Block in 30 Minutes With ACF<\/a><\/blockquote><iframe class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\" title=\"&#8220;Building a Custom Slider Block in 30 Minutes With ACF&#8221; &#8212; ACF\" src=\"https:\/\/www.advancedcustomfields.com\/blog\/building-a-custom-slider-block-in-30-minutes-with-acf\/embed\/#?secret=pfjmXh6sww#?secret=BxyS0AP3Rt\" data-secret=\"BxyS0AP3Rt\" width=\"600\" height=\"338\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n\n\n\n<p><a href=\"https:\/\/www.loom.com\/embed\/6e357b8d23324450bf642e7b8bba507e\">https:\/\/www.loom.com\/embed\/6e357b8d23324450bf642e7b8bba507e<\/a><\/p>\n\n\n\n<!--more-->\n\n\n\n<h4 class=\"wp-block-heading\"> Theme setup<\/h4>\n\n\n\n<p>Create a folder and files for your custom block:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>- templates\n  - blocks\n    - slider\n      - slider.js\n      - slider.php\n      - slider.scss<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"> Documentation and Examples<\/h4>\n\n\n\n<p><a href=\"https:\/\/www.advancedcustomfields.com\/resources\/blocks\/\">https:\/\/www.advancedcustomfields.com\/resources\/blocks\/<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/www.advancedcustomfields.com\/resources\/acf_register_block_type\/\">https:\/\/www.advancedcustomfields.com\/resources\/acf_register_block_type\/<\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Register a block<\/h4>\n\n\n\n<ul><li>Note: all the code assumes a Sage 8 theme (that is what I use)<\/li><\/ul>\n\n\n\n<p>Grab the code from the <a href=\"https:\/\/www.advancedcustomfields.com\/resources\/acf_register_block_type\/\">&nbsp;acf_register_block_type<\/a> page, and adapt it for our slider (and the Sage theme)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>add_action('acf\/init', __NAMESPACE__ .'\\\\my_register_blocks');\nfunction my_register_blocks() {\n\n    \/\/ check function exists.\n    if( function_exists('acf_register_block_type') ) {\n\n        \/\/ Register a testimonial block.\n        acf_register_block_type(array(\n            'name'              => 'slider',\n            'title'             => __('Slider'),\n            'description'       => __('A custom slider block.'),\n            'render_template'   => get_template_directory() . '\/templates\/blocks\/slider\/slider.php',\n            'category'          => 'formatting',\n            'icon'              => 'images-alt2',\n        ));\n    }\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Enqueue block assets. <\/h4>\n\n\n\n<p>We will use the following jquery slider for our slider block:<\/p>\n\n\n\n<p><a href=\"https:\/\/kenwheeler.github.io\/slick\/\">https:\/\/kenwheeler.github.io\/slick\/<\/a><\/p>\n\n\n\n<p>We will have to enqueue the dependencies for this slider using <em>enqueue_assets<\/em><\/p>\n\n\n\n<p>Again: copy the code from the <a href=\"https:\/\/www.advancedcustomfields.com\/resources\/acf_register_block_type\/\">&nbsp;acf_register_block_type<\/a> page. We are using the callback function <em>enqueue_assets<\/em>, and we add it to our block registration code. <\/p>\n\n\n\n<p><strong>Note: <\/strong>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.<\/p>\n\n\n\n<p>Also use the CDN links from the <a href=\"https:\/\/github.com\/kenwheeler\/slick\/\">Slick github <\/a>page to enqueue the <em>Slick<\/em> assets<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>add_action('acf\/init', __NAMESPACE__ .'\\\\my_register_blocks');\nfunction my_register_blocks() {\n\n    \/\/ check function exists.\n    if( function_exists('acf_register_block_type') ) {\n\n        \/\/ Register a testimonial block.\n        acf_register_block_type(array(\n            'name'              => 'slider',\n            'title'             => __('Slider'),\n            'description'       => __('A custom slider block.'),\n            'render_template'   => get_template_directory() . '\/templates\/blocks\/slider\/slider.php',\n            'category'          => 'formatting',\n            'icon'              => 'images-alt2',\n            'enqueue_assets' => function(){\n              wp_enqueue_style( 'slick', 'http:\/\/cdn.jsdelivr.net\/npm\/slick-carousel@1.8.1\/slick\/slick.css', array(), '1.8.1' );\n              wp_enqueue_style( 'slick-theme', 'http:\/\/cdn.jsdelivr.net\/npm\/slick-carousel@1.8.1\/slick\/slick-theme.css', array(), '1.8.1' );\n              wp_enqueue_script( 'slick', 'http:\/\/cdn.jsdelivr.net\/npm\/slick-carousel@1.8.1\/slick\/slick.min.js', array('jquery'), '1.8.1', true);\n\n\/\/wp_enqueue_style( 'block-slider', get_template_directory_uri() . '\/templates\/blocks\/slider\/slider.min.scss', array(), '1.0.0' );\n\n\/\/wp_enqueue_script( 'block-slider', get_template_directory_uri() . '\/templates\/blocks\/slider\/slider.min.js', array('jquery'), '1.0.0', true );\n            }\n        ));\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>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<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wp_enqueue_script( 'blocks', get_template_directory_uri() . '\/assets\/scripts\/blocks\/slider.js', array('slick'), '1.0.0', true );<\/code><\/pre>\n\n\n\n<p>The asset are placed like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Assets\n  scripts\n    blocks\n      slider.js\n  styles\n    blocks\n      _slider.scss<\/code><\/pre>\n\n\n\n<p>The slider.js file is added to blocks.js in manifest.json<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"dependencies\": {\n    \"main.js\": {\n      \"files\": [\n        \"scripts\/main.js\"\n      ],\n      \"main\": true\n    },\n    \"blocks.js\": {\n      \"files\": [\n        \"scripts\/blocks\/slider.js\"\n      ]\n    },<\/code><\/pre>\n\n\n\n<p>And blocks is enqueued (with slick as dependency) as already shown<\/p>\n\n\n\n<p>The _slider.scss file is simply imported in main.scss like the other scss files<\/p>\n\n\n\n<p><strong>The block should now be visible in the WP editor, (although it does nothing yet)<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"366\" height=\"341\" src=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-3.png\" alt=\"\" class=\"wp-image-11360\" srcset=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-3.png 366w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-3-150x140.png 150w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-3-300x280.png 300w\" sizes=\"(max-width: 366px) 100vw, 366px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Create fields<\/h4>\n\n\n\n<p>Let&#8217;s create a very simple repeater image field for the slider:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"265\" height=\"107\" src=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-4.png\" alt=\"\" class=\"wp-image-11363\" srcset=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-4.png 265w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-4-150x61.png 150w\" sizes=\"(max-width: 265px) 100vw, 265px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"655\" height=\"298\" src=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-5.png\" alt=\"\" class=\"wp-image-11364\" srcset=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-5.png 655w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-5-150x68.png 150w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-5-300x136.png 300w\" sizes=\"(max-width: 655px) 100vw, 655px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"797\" height=\"713\" src=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-6.png\" alt=\"\" class=\"wp-image-11365\" srcset=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-6.png 797w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-6-150x134.png 150w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-6-300x268.png 300w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-6-768x687.png 768w\" sizes=\"(max-width: 797px) 100vw, 797px\" \/><\/figure>\n\n\n\n<p>As the location you should now be able to select the &#8216;slides&#8217; block:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"982\" height=\"106\" src=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-7.png\" alt=\"\" class=\"wp-image-11366\" srcset=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-7.png 982w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-7-150x16.png 150w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-7-300x32.png 300w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-7-768x83.png 768w\" sizes=\"(max-width: 982px) 100vw, 982px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">\nCreate block HTML\n\n<\/h4>\n\n\n\n<p> Grab the example template from the <a href=\"https:\/\/www.advancedcustomfields.com\/resources\/acf_register_block_type\/\">&nbsp;acf_register_block_type<\/a> page and paste it in your slider.php file and adapt it to your slider block<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n\n\/**\n * Slider Block Template.\n *\n * @param   array $block The block settings and attributes.\n * @param   string $content The block inner HTML (empty).\n * @param   bool $is_preview True during AJAX preview.\n * @param   (int|string) $post_id The post ID this block is saved to.\n *\/\n\n\/\/ Create id attribute allowing for custom \"anchor\" value.\n$id = 'slider' . $block['id'];\nif( !empty($block['anchor']) ) {\n    $id = $block['anchor'];\n}\n\n\/\/ Create class attribute allowing for custom \"className\" and \"align\" values.\n$className = 'slider';\nif( !empty($block['className']) ) {\n    $className .= ' ' . $block['className'];\n}\nif( !empty($block['align']) ) {\n    $className .= ' align' . $block['align'];\n}\n\n?>\n&lt;div id=\"&lt;?php echo esc_attr($id); ?>\" class=\"&lt;?php echo esc_attr($className); ?>\">\n    &lt;?php if( have_rows('slides') ): ?>\n        &lt;div class=\"slides\">\n            &lt;?php while( have_rows('slides') ): the_row();\n                $image = get_sub_field('image');\n                ?>\n                &lt;div>\n                    &lt;?php echo wp_get_attachment_image( $image['id'], 'full' );?>\n                &lt;\/div>\n            &lt;?php endwhile; ?>\n        &lt;\/div>\n    &lt;?php else: ?>\n        &lt;!-- Necessary, to make sure there is something when the block is still empty in admin -->\n        &lt;p>Please add some slides&lt;\/p>\n    &lt;?php endif; ?>\n&lt;\/div><\/code><\/pre>\n\n\n\n<p><strong>You should now see this when you add a slider block to a page:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"642\" height=\"134\" src=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-8.png\" alt=\"\" class=\"wp-image-11373\" srcset=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-8.png 642w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-8-150x31.png 150w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-8-300x63.png 300w\" sizes=\"(max-width: 642px) 100vw, 642px\" \/><\/figure>\n\n\n\n<p>And in the sidebar you should be able to add slides to this block<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"> Create block JavaScript. <\/h4>\n\n\n\n<p> Grab the example template (testimonial.js) for js at the <a href=\"https:\/\/www.advancedcustomfields.com\/resources\/acf_register_block_type\/\">&nbsp;acf_register_block_type<\/a> page and paste it in your slider.js file and adapt it.<\/p>\n\n\n\n<p>For this example we use the js code for the &#8216;Variable Width&#8217; slider on the <a href=\"https:\/\/kenwheeler.github.io\/slick\/\">Slick page<\/a>:<\/p>\n\n\n\n<p>$(&#8216;.variable-width&#8217;).slick({<br>\n            dots: true,<br>\n            infinite: true,<br>\n            speed: 300,<br>\n            slidesToShow: 1,<br>\n            centerMode: true,<br>\n            variableWidth: true<br>\n        });<\/p>\n\n\n\n<p>And put that in the initializeBlock function<\/p>\n\n\n\n<p><strong>Note:&nbsp;<\/strong>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). <\/p>\n\n\n\n<p>$block.find(&#8216;.slides&#8217;).slick({<br>  &#8230; <\/p>\n\n\n\n<p>Of course you can add\/change other slick options if you want<\/p>\n\n\n\n<p><strong>The slider should now work!<\/strong> <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Styling the block<\/h4>\n\n\n\n<p>You can now make some changes to the styles of the slider if you want.<\/p>\n\n\n\n<p><strong>NOTE<\/strong>: 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). <br>See the solution under &#8216;Admin problems&#8217; to apply styles ot the backend anyway.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Fix admin problems<\/h4>\n\n\n\n<p><strong>Fix selectable issue <\/strong><\/p>\n\n\n\n<p>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. <\/p>\n\n\n\n<p>To fix this we can make use of the variable <em>$is_preview<\/em> that we can see in the Block template<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"637\" height=\"192\" src=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-9.png\" alt=\"\" class=\"wp-image-11383\" srcset=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-9.png 637w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-9-150x45.png 150w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-9-300x90.png 300w\" sizes=\"(max-width: 637px) 100vw, 637px\" \/><\/figure>\n\n\n\n<p><em>$is_preview&nbsp;<\/em>is true when you are in the backend<\/p>\n\n\n\n<p>So we can apply a class to the block only when <em>$is_preview<\/em> is True.<\/p>\n\n\n\n<p>Add this to the block template:<\/p>\n\n\n\n<p>if( $is_preview ){<br>     $className .= &#8216; is-preview&#8217;;<br> }<\/p>\n\n\n\n<p>Result in the backend:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"496\" height=\"81\" src=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-10.png\" alt=\"\" class=\"wp-image-11384\" srcset=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-10.png 496w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-10-150x24.png 150w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-10-300x49.png 300w\" sizes=\"(max-width: 496px) 100vw, 496px\" \/><\/figure>\n\n\n\n<p>Now add the following style to the stylesheet of the block:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.slider.is-preview:before {\n  content: '';\n  display: block;\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  \/*background: red;*\/ \n  z-index: 1;\n}<\/code><\/pre>\n\n\n\n<p><strong>NOTE<\/strong>: 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). <\/p>\n\n\n\n<p>So I have a separate blocks.css in the theme root folder, which is enqueued as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/**\n * Enqueue Gutenberg scripts and styles to backend area.\n *\/\nfunction my_gutenberg_assets() {\n  wp_enqueue_style( 'my-gutenberg-admin', get_stylesheet_directory_uri() . '\/blocks.css', array(), '1.0.0' );\n}\nadd_action( 'enqueue_block_assets', __NAMESPACE__ . '\\\\my_gutenberg_assets' );<\/code><\/pre>\n\n\n\n<p>This overlays an invisible element over the block so that clicks won&#8217;t cause problems anymore.<\/p>\n\n\n\n<p>Another problem: when adding a block below the slider, the + overlaps the controls of the slider:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"668\" height=\"195\" src=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-11.png\" alt=\"\" class=\"wp-image-11386\" srcset=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-11.png 668w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-11-150x44.png 150w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-11-300x88.png 300w\" sizes=\"(max-width: 668px) 100vw, 668px\" \/><\/figure>\n\n\n\n<p>To fix this we will add margin below the slider block<\/p>\n\n\n\n<p>.slider.is-preview {<br>   margin-bottom: 70px;<br> }<\/p>\n\n\n\n<p>Result: <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"726\" height=\"212\" src=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-12.png\" alt=\"\" class=\"wp-image-11388\" srcset=\"https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-12.png 726w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-12-150x44.png 150w, https:\/\/hesmid.nl\/test\/wp-content\/uploads\/2019\/07\/image-12-300x88.png 300w\" sizes=\"(max-width: 726px) 100vw, 726px\" \/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>https:\/\/www.loom.com\/embed\/6e357b8d23324450bf642e7b8bba507e<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"acf":[],"_links":{"self":[{"href":"https:\/\/hesmid.nl\/test\/wp-json\/wp\/v2\/posts\/11354"}],"collection":[{"href":"https:\/\/hesmid.nl\/test\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hesmid.nl\/test\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hesmid.nl\/test\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/hesmid.nl\/test\/wp-json\/wp\/v2\/comments?post=11354"}],"version-history":[{"count":17,"href":"https:\/\/hesmid.nl\/test\/wp-json\/wp\/v2\/posts\/11354\/revisions"}],"predecessor-version":[{"id":13339,"href":"https:\/\/hesmid.nl\/test\/wp-json\/wp\/v2\/posts\/11354\/revisions\/13339"}],"wp:attachment":[{"href":"https:\/\/hesmid.nl\/test\/wp-json\/wp\/v2\/media?parent=11354"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hesmid.nl\/test\/wp-json\/wp\/v2\/categories?post=11354"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hesmid.nl\/test\/wp-json\/wp\/v2\/tags?post=11354"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}