Advanced Block Development: Part One

Introduction

Learn how to build more interactive blocks for a more engrossing user experience. Topics covered in these videos:

  • Prevent content in your block from conflicting with the edit mode.
  • Find out what page you are currently on, and get an object representing it.
  • Create special views for the scrapbook interface.
  • Use validation in your block.
  • Make your block show up in search
  • Integrate it with composer
  • Use the file manager
  • Set up its caching options
  • Create actions for user input

Note that this is a live recording of a training session between Andrew and the trainees, so the topics are addressed as they come up.

Just as a reminder, all of a core block's views are going to be at concrete/blocks/blockname/view.php but its controller will be at concrete/core/controllers/blocks/blockname.php

Let's get started

The google maps block is a good reference overall. The video and youtube blocks show how to make your placeholder "content" the same size as what site visitors see. All of these blocks do "advanced" things, but their code is fairly simple and easy to read.

Here is how to check if the block is on a page that is being edited:

$c = Page::getCurrentPage(); // get an object of the current page.
if ($c->isEditMode()) { ?> // check out concrete/core/models/page.php 
                                     // and concrete/core/models/collection.php 
                                     // to see all available functions
    /* this is placeholder code rendered during edit mode*/
 }?>

The file scrapbook.php in a block is a special view for the scrapbook interface. It can be thought of as a special template that will only be shown when the scrapbook or copy / paste dialog is open. Check out the google_map or html blocks scrapbook.php files vs their view.php to see this in practice.

Blocks give you two options for validating input: client side or server side. As noted in basic block development, auto.js gets loaded when the add / edit dialog is open. If the file has a function ccmValidateBlockForm, this can be used to validate user input.

Here is a client-side validation from the image block's auto.js:

 ccmValidateBlockForm = function() {
    if ($("#ccm-b-image-fm-value").val() == '' || $("#ccm-b-image-fm-value").val() == 0) { 
       ccm_addError(ccm_t('image-required'));
    }
    return false;
 }

That ccm_t function is a translation function. It will read a javascript variable image-required that was included in the source file server-side, using concrete5's t() translation function. Those variables are configured in the blocks controller. In this example, here is the relevant code in the image block's controller.php

    public function getJavaScriptStrings() {
        return array(
            'image-required' => t('You must select an image.')
        );
    }

This is useful for when you need to add some translatable content to your javascript, but it's actually kind of a hassle to do this for validation. If you were needing some data from the server to know if this is a valid setting for a block, you would need to include AJAX calls in that ccmValidateBlockForm.

The other option for validation is on the server side. This is useful in the case where you need to validate against something more involved than "is this a number", or you just don't feel like adding that extra code so the error message is translatable.

Here is the code from the file block's controller:

    public function validate($args) {
        $e = Loader::helper('validation/error');
        if ($args['fID'] < 1) {
            $e->add(t('You must select a file.'));
        }
        if (trim($args['fileLinkText']) == '') {
            $e->add(t('You must give your file a link.'));
        }
        return $e;
    }

and a more succinct generic example:

    public function validate($args) {
        $e = Loader::helper('validation/error');
        if (condition) {
            $e->add(t('This had a problem'));
        }
        return $e;
    }

The way the error validation helper works is that even though that error object is always being returned from the validate function, it will only actually cause an error to happen when it contains more than zero actual errors. Check out core/helpers/validation/error.php to see everything about it.

That function gets called before the save() function runs, so the person editing the site will not have to re-start adding the block that that they were trying to add, they just need to correct what's wrong.


Recent Discussions on this Topic

Custom Block View Tutorial

Attached is a white paper on creating custom block views. I am finding many C5 users do not understand this concept and even hesitate to modify purchased addons. I hope this is helpful. Please PM me if you have any additions or corrections and I …

Building a block with library image input?

I'm trying to build a block that has the ability to pull an image from the library (or, since I'm desperate, from anywhere, even a remote URL), but I can't figure it out, and I'm new to PHP... Does anyone have any pointers? I tried reading http://phple…

Adding smarter DISQUS to your concrete5

Guys, I've just finished figuring out a smarter way to implement Disqus, a third-party commenting system Sometime, you don't bother users to register on your site, but comment using Facebook, twitter or other social ID. Disqus is a fine comment s…

Check it out: custom block creator!

*** This package is now available on the marketplace: http://www.concrete5.org/marketplace/addons/designer-content/ *** I've made a "custom block creator" which aims to solve the problem of allowing you (as the site designer) to specify exactly how som…

Check if block is empty

Hi guys, I need some help with this: I need to check if a block is empty (essentially the 'C' field). If the 'C' (content?) field is empty I want serve a conditional accordingly. I have tried the following unsuccessfully; [code] $block = Block::getBy…