Package Processes


Let us know by posting here.

Centralized Help Registry for Packages

Create a Help Service Provider in your package to manage help messages centrally. This is useful when one person manages help for various blocks and Dashboard pages.

Package-Based Help

Familiarity with building a Concrete Package is assumed.

Implementation Steps

Assuming a package named "acme_widgets", the controller will be \Concrete\Package\AcmeWidgets\Controller in packages/acme_widgets/controller.php.

  1. Enable advanced autoloading in your package controller:

    protected $pkgAutoloaderMapCoreExtensions = true;
  2. Create HelpServiceProvider in packages/acme_widgets/src/Concrete/Help/HelpServiceProvider.php:

    namespace Concrete\Package\AcmeWidgets\Help;
    use Concrete\Core\Foundation\Service\Provider;
    class HelpServiceProvider extends Provider
        public function register()
            // Help messages will be added here
  3. In your package on_start() method, register your service provider:

    public function on_start()
        $app = Core::make('app');
        $provider = new \Concrete\Package\AcmeWidgets\Help\HelpServiceProvider($app);
  4. Define help messages in register() method of HelpServiceProvider:

    public function register()
        $this->app['help/block_type']->registerMessageString('plain_text_box', 'Plain Text Box Help');
        $this->app['help/block_type']->registerMessageString('dummy_block', 'Other help text.');
        $this->app['help/dashboard']->registerMessageString('/dashboard/acme_widgets/add', t('Add a Widget.'));

This setup allows you to control all help messages from a single location in your package.

Install Content with CIF

Use the Concrete Interchange Format (CIF) in XML files for easier package installation in Concrete CMS, including single pages, user attributes, and jobs. Implement this by adding to your package's controller.php:

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

    public function upgrade()

    private function installXml()

Start the CIF XML file with:

<?xml version="1.0"?>
<concrete5-cif version="1.0">

End with:


Write the XML definitions for installation between these lines. Use examples from concrete/config/install/ or generate XML using the Concrete Migration Tool.

For specific implementations like defining attribute keys, refer to CIF Example - Attribute Keys.

Programmatically Creating Composer Forms and Controls


Creating a page type with a default layout and an easy-to-edit composer form enhances user experience and usability. It simplifies page creation, ensuring users don't have to worry about block placement.

Example Specification

We'll create a Composer form for a Country listing page type, including attributes like map, name, population, and capital city. The attributes are already added to the Page Type (refer to Adding Attribute Sets and Keys Programmatically and Adding Page Types Programmatically).


Include necessary classes in the controller if Page Types and Attributes aren't created programmatically:

use PageType;
use \Concrete\Core\Attribute\Key\CollectionKey as CollectionKey;

Layout Sets

Layout sets group information on the Composer form. For a single 'Country Info' set:

use \Concrete\Core\Page\Type\Composer\LayoutSet as LayoutSet;

$pt = PageType::getByHandle('country);
$countrySet = $pt->addPageTypeComposerFormLayoutSet('Country Info', 'Country Info');

Form Controls

Add controls for Blocks, Built-In Properties, and Custom Attributes.

Built-in Attributes

Order matters, start with the Country Name:

use \Concrete\Core\Page\Type\Composer\Control\CorePageProperty\NameCorePageProperty as NameControl;

$countryName = new NameControl();
$countryControl = $countryName->addToPageTypeComposerFormLayoutSet($countrySet);
$countryControl->updateFormLayoutSetControlCustomLabel('Country Name');
$countryControl->updateFormLayoutSetControlDescription('Enter a Country Name for the Page Name');

Block Controls

Add map and description using built-in blocks:

use BlockType;
use \Concrete\Core\Page\Type\Composer\Control\BlockControl as BlockControl;

$countryMap = new BlockControl();
$imageBlock = BlockType::getByHandle('image');

$countryDesc = new BlockControl();
$descBlockID = BlockType::getByHandle('content')->getBlockTypeID();

Custom Attributes

Add attributes for population and capital city:

use \Concrete\Core\Attribute\Key\CollectionKey as CollectionKey;
use \Concrete\Core\Page\Type\Composer\Control\CollectionAttributeControl as AttributeControl;

$countryCapital = new AttributeControl();
$capitalID = CollectionKey::getByHandle('capital')->getAttributeKeyID();