10 min read

 

concrete5 Beginner’s Guide

concrete5 Beginner's Guide

Create and customize your own website with the Concrete5 Beginner’s Guide

What’s a package?

Before we start creating our package, here are a few words about the functionality and purpose of packages:

  • They can hold a single or several themes together
  • You can include blocks which your theme needs
  • You can check the requirements during the installation process in case your package depends on other blocks, configurations, and so on
  • A package can be used to hook into events raised by concrete5 to execute custom code during different kind of actions
  • You can create jobs, which run periodically to improve or check things in your website

These are the most important things you can do with a package; some of it doesn’t depend on packages, but is easier to handle if you use packages. It’s up to you, but putting every extension in a package might even be useful if there’s just a single element in it—why?

  • You never have to worry where to extract the add-on. It always belongs in the packages directory
  • An add-on wrapped in a package can be submitted to the concrete5 marketplace allowing you to earn money or make some people in the community happy by releasing your add-on for free

Package structure

We’ve already looked at different structures and you are probably already familiar with most of the directories in concrete5. Before we continue, here are a few words about the package structure, as it’s essential that you understand its concept before we continue.

A package is basically a complete concrete5 structure within one directory. All the directories are optional though. No need to create all of them, but you can create and use all of them within a single package. The directory concrete is a lot like a package as well; it’s just located in its own directory and not within packages.

Package controller

Like the blocks we’ve created, the package has a controller as well. First of all, it is used to handle the installation process, but it’s not limited to that. We can handle events and a few more things in the package controller; there’s more about that later in this article.

For now, we only need the controller to make sure the dashboard knows the package name and description.

Time for action – creating the package controller

Carry out the following steps:

  1. First, create a new directory named c5book in packages.
  2. Within that directory, create a file named controller.php and put the following content in it:

    <?php
    defined(‘C5_EXECUTE’) or die(_(“Access Denied.”));
    class c5bookPackage extends Package {

    protected $pkgHandle = ‘c5book’;
    protected $appVersionRequired = ‘5.4.0’;
    protected $pkgVersion = ‘1.0’;
    public function getPackageDescription() {
    return t(“Theme, Templates and Blocks from
    concrete5 for Beginner’s”);
    }
    public function getPackageName() {
    return t(“c5book”);
    }

    public function install() {
    $pkg = parent::install();
    }
    }
    ?>

    
    
  3. You can create a file named icon.png 97 x 97 pixels with 4px rounded transparent corners. This is the official specification that you have to follow if you want to upload your add-on to the concrete5 marketplace.
  4. Once you’ve created the directory and the mandatory controller, you can go to your dashboard and click on Add Functionality. It looks a lot like a block but when you click on Install, the add-on is going to appear in the packages section.

    concrete5 tutorial

What just happened?

The controller we created looks and works a lot like a block controller, which you should have seen and created already. However, let’s go through all the elements of the package controller anyway, as it’s important that you understand them:

  • pkgHandle: A unique handle for your package. You’ll need this when you access your package from code.
  • appVersionRequired: The minimum version required to install the add-on. concrete5 will check that during the installation process.
  • pkgVersion: The current version of the package. Make sure that you change the number when you release an update for a package; concrete5 has to know that it is installing an update and not a new version.
  • getPackageDescription: Returns the description of your package. Use the t-function to keep it translatable.
  • getPackageName: The same as above, just a bit shorter.
  • install: You could remove this method in the controller above, since we’re only calling its parent method and don’t check anything else. It has no influence, but we’ll need this method later when we put blocks in our package. It’s just a skeleton for the next steps at the moment.

Moving templates into package

Remember the templates we’ve created? We placed them in the top level blocks directory. Worked like a charm but imagine what happens when you create a theme which also needs some block templates in order to make sure the blocks look like the theme? You’d have to copy files into the blocks directory as well as themes. This is exactly what we’re trying to avoid with packages.

It’s rather easy with templates; they work almost anywhere. You just have to copy the folder slideshow from blocks to packages/c5book/blocks, as shown in the following screenshot:

concrete5 tutorial

This step was even easier than most things we did before. We simply moved our templates into a different directory—nothing else.

concrete5 looks for custom templates in different places like:

  • concrete/blocks/<block-name>/templates
  • blocks/<block-name>/templates
  • packages/<package-name>/blocks/<block-name>/templates

It doesn’t matter where you put your templates, concrete5 will find them.

Moving themes and blocks into the package

Now that we’ve got our templates in the package, let’s move the new blocks we’ve created into that package as well. The process is similar, but we have to call a method in the installer which installs our block. concrete5 does not automatically install blocks within packages.

This means that we have to extend the empty install method shown earlier.

Before we move the blocks into the package you should remove all blocks first. To do this, go to your dashboard, click on Add Functionality, click on the Edit button next to the block you want to move, and click on the Remove button in the next screen. We’ll start with the jqzoom block.

Please note; removing a block will of course, remove all the blocks you’ve added to your pages. Content will be lost if you move a block into a package after you’ve already used it.

Time for action – moving jQZoom block into the package

Carry out the following steps:

  1. As mentioned earlier, remove the jqzoom block from you website by using the Add Functionality section in your dashboard.
  2. Move the directory blocks/jqzoom to packages/c5book/blocks.
  3. Open the package controller we created a few pages earlier; you can find it at packages/c5book/controller.php. The following snippet shows only a part of the controller, the install method. The only thing you have to do is insert the highlighted line:

    public function install() {
    $pkg = parent::install();

    // install blocks
    BlockType::installBlockTypeFromPackage(‘jqzoom’, $pkg);
    }

    
    
  4. Save the file and go to your dashboard again. Select Add Functionality and locate the c5book package; click on Edit and then Uninstall Package and confirm the process on the next screen. Back on the Add Functionality screen, reinstall the package again, which will automatically install the block.

What just happened?

Besides moving files, we only had to add a single line of code to our existing package controller. This is necessary, because blocks within packages aren’t automatically installed. When installing a package, only the install method of the controller is called, exactly the place where we hook into and install our block.

The installBlockTypeFromPackage method takes two parameters: The block handle and the package object. However, this doesn’t mean that packages behave like namespaces. What does this mean?

  • A block is connected to a package. This is necessary in order to be able to uninstall the block when removing the package along with some other reasons.
  • Even though there’s a connection between the two objects, a block handle must be unique across all packages.

You’ve seen that we had to remove and reinstall the package several times while we only moved a block. At this point, it probably looks a bit weird to do that, especially as you’re going to lose some content on your website.

However, when you’re more familiar with the concrete5 framework, you’ll usually know if you’re going to need a package and make that decision before you start creating new blocks. If you’re still in doubt, don’t worry about it too much and create a package and not just a block. Using a package is usually the safest choice.

Don’t forget that all instances of a block will be removed from all pages when you uninstall the block from your website. Make sure your package structure doesn’t change before you start adding content to your website.

Time for action – moving the PDF block into the package

Some blocks depend on helpers, files and libraries, which aren’t in the block directory. The PDF generator block is such an example. It depends on a file found in the tools directory in the root of your concrete5 website. How do we include such a file in a package?

  1. Move the pdf directory from blocks to packages/c5book/blocks since we also want to include the block in the package.
  2. Locate the c5book directory within packages and create a new subdirectory named tools.
  3. Move generate_pdf.php from tools to packages/c5book/tools.
  4. Create another directory named libraries in packages/c5book.
  5. Move the mpdf50 from libraries to packages/c5book/libraries. As we’ve moved two objects, we have to make sure our code looks for them in the right place. Open packages/c5book/tools/generate.php and look for Loader::library at the beginning of the file. We have to add a second parameter to Loader::library, as shown here:

    <?php
    defined(‘C5_EXECUTE’) or die(_(“Access Denied.”));

    Loader::library(‘mpdf50/mpdf’, ‘c5book’);
    $fh = Loader::helper(‘file’);

    $header = <<<EOT
    <style type=”text/css”>
    body { font-family: Helvetica, Arial; }
    h1 { border-bottom: 1px solid black; }
    </style>
    EOT;

    
    
  6. Next, open packages/c5book/blocks/pdf/view.php. We have to add the package handle as the second parameter to make sure the tool file is loaded from the package.

    <!–hidden_in_pdf_start–>
    <?php
    defined(‘C5_EXECUTE’) or die(_(‘Access Denied.’));

    $nh = Loader::helper(‘navigation’);
    $url = Loader::helper(‘concrete/urls’);

    $toolsUrl = $url->getToolsURL(‘generate_pdf’, ‘c5book’);
    $toolsUrl .= ‘?p=’ . rawurlencode($nh->getLinkToCollection($this-
    >c, true));

    echo “<a href=”{$toolsUrl}”>PDF</a>”;

    ?>
    <!–hidden_in_pdf_end–>

    
    

What just happened?

In the preceding example, we put got a file in the tools directory and a PDF generator in the libraries directory, which we had to move as well.

Even at the risk of saying the same thing several times: A package can contain any element of concrete5—libraries, tools, controllers, images, and so on. By putting all files in a single package directory, we can make sure that all files are installed at once, thus making sure all dependencies are met.

Nothing has changed beside the small changes we’ve made to the commands, which access or load an element. A helper behaves like a helper, no matter where it’s located.

Have a go hero – move more add-ons

We’ve moved two different blocks into our new package, along with the slideshow block templates. These aren’t all blocks we’ve created so far. Try to move all add-ons we’ve created into our new package. If you need more information about that process, have a look at the following page:

http://www.concrete5.org/documentation/developers/system/packages/

LEAVE A REPLY

Please enter your comment!
Please enter your name here