Creating Attribute Keys in a Package

Was this information useful?
Thank you for your feedback.

The most common thing a developer might do with a custom attribute is creating one programmatically for use in a package. For example, in our Property Manager package, let's say we're using pages to display our houses, and we'd like to do the following:

  1. Add a general purpose checkbox attribute that determines whether a page's sub-pages should be excluded from navigation.
  2. Add a new instance of the Property Location custom attribute we just installed with our custom package (and set its custom setting to display as a Radio List)
  3. Add a Property Image custom thumbnail Image/File attribute type.

We're going to be using these custom attributes in our block and theme templates, so we need to make sure they're available. Fortunately it's easy to create these through code right in our package controller file (or in a separate installation file.)

First, if you haven't, check out the documentation on packaging a theme. Here you'll learn the ins and outs on the Concrete CMS package format, a package's controller file and get up to speed quickly.

Once you have your package's controller file created, it's a simple matter to create our first custom attribute key. First, import the Concrete\Core\Entity\Attribute\Key\PageKey class namespace at the top of the controller, as you're going to need it.

use Concrete\Core\Entity\Attribute\Key\PageKey;

First, get the category object for the page attribute category. Since we're adding page attributes, this is the only category object we'll need to be concerned with. You can retrieve the category object this way:

$service = $this->app->make('Concrete\Core\Attribute\Category\CategoryService');
$categoryEntity = $service->getByHandle('collection');
$category = $categoryEntity->getController();

Now that we have $category, an instance of the Concrete\Core\Attribute\Category\PageCategory class, we can add attribute keys to it.

Attribute 1: Exclude Subpages from Nav

Let's add our boolean attribute. It's a good idea to check to see if the attribute key exists before trying to install it.

$key = $category->getByHandle('exclude_subpages_from_nav');
if (!is_object($key)) {
    $key = new PageKey();
    $key->setAttributeKeyName('Exclude Subpages from Nav');
    $key = $category->add('boolean', $key, null, $pkg);

That's it! You an set any parameters you want set a certain way on the key object directly on the key entity, before you pass it into the add() method. The first parameter is the text handle of the attribute type you want to add. The third null parameter is the relevant Concrete\Core\Entity\Attribute\Key\Settings object; if you don't provide one the default will be used. Finally, the package entity goes in as the fourth parameter.

Attribute 2: Property Location Custom Attribute

Now, let's add our custom property location custom attribute in this package. Since we want to actually create this key with some custom settings, let's import the custom settings namespace at the top of the controller file:

use Concrete\Package\PropertyManager\Entity\Attribute\Key\Settings\PropertyLocationSettings;

Now, create the attribute:

$key = $category->getAttributeKeyByHandle('location');
if (!is_object($key)) {
    $key = new PageKey();

    $settings = new PropertyLocationSettings();

    $key = $category->add('property_location', $key, $settings, $pkg);

And with that, we have added our custom property location attribute, with the handle 'location'.

Attribute 3: Image/File Attribute

Finally, let's add our image/file attribute. Since we have no settings for this that we wish to change, we can just add the following code to the install() method:

$key = $category->getByHandle('property_thumbnail');
if (!is_object($key)) {
    $key = new PageKey();
    $key = $category->add('image_file', $key, null, $pkg);