Programmatically creating attributes, objects etc in Concrete5

Once you start doing more interesting stuff with Concrete5, you’ll quickly discover that it suffers from a lack of proper documentation. It took me hours of googling and digging through C5 source to find some parts of the following information. For future reference, I’m compiling it all into one post.

Programmatically creating a page type

// Check if the page type already exists
$pageType = CollectionType::getByHandle("page_type_handle");
if (!$pageType || !intval($pageType->getCollectionTypeID())) {
        'ctHandle' => "page_type_handle",
        'ctName' => t('Human Readable Page Type Name')
    ), $this->pkg);
} else {
    Log::addEntry("Page Type already exists, skipping creation.", 'Debug');

The last argument, $this->pkg may be left out if you are not calling this function from a package.

Programmatically creating a group

$groupName = "Human Readable Group Name";
$groupDesc = "Group description.";
if (!is_object(Group::getByName($groupName))) {
    Group::add($groupName, $groupDesc);
} else {
    Log::addEntry("Group {$groupName} already exists, skipping creation.", 'Debug');

Groups only have the ID and human readable name as the identifier.

Programmatically create a page…

To create a new page, you have to get the new page type object and attach the new page to a parent page.

$newPageType = CollectionType::getByHandle('page_type_handle');
$parentPage = Page::getByPath('/whatever');

$newPage = $parentPage->add($newPageType, array(
    'name' => 'New page name',
    'cHandle' => 'new_page_handle',
    'cDescription' => 'New page description',
    'cDatePublic' => date('Y-m-d H:i:s') // Note the format

$newPage->setAttribute('exclude_nav', true); // This is how you set attributes to a page

 .. set the page’s group permissions ..

I believe this is the “simple” permissions model for v5.6:

    Group::getByName("Human Readable Group Name"), 

$newPage->refreshCache(); // this is important

What seems to be the full list of permissions (from here – thanks brianvandelden):


Note that I have personally not tested these and documentation is difficult to find.

.. create a block and attach it to the created page

$contentBlock = BlockType::getByHandle('block_handle');
$blockData = array(
    'content' => 'The usual block "content" field',
    'field_1_textarea_text' => 'If you're using Designer Content, this is the typical syntax'

// Note that this is case sensitive and has to be EXACTLY the same as the area name you use in your template.
$areaName = 'Main'; 
$newBlock = $newPage->addBlock($contentBlock, $areaName, $blockData);

Programmatically creating a Single Page

$singlePage = SinglePage::add('/dashboard/path/to/wherever', $this->pkg);
if (is_null($singlePage)) {
    Log::addEntry("Single page '/dashboard/path/to/wherever' already exists. Please remove it and re-install this package.", 'Debug');
} else {
        'cName' => 'Human Readable Single Page Name',
        'cDescription' => 'Page description'

Programmatically creating a Select attribute type..

$selectAttributeType = AttributeType::getByHandle('select');

$selectAttribute = CollectionAttributeKey::add($type, array(
    'akHandle' => 'attribute_key_handle', 
    'akName' => 'Attribute Key Name',
    'akIsSearchable' => false,
    'akSelectAllowOtherValues' => true
), $this->pkg);

This creates a Select attribute that is not searchable and allows selecting multiple values.

Again, the last argument, $this->pkg may be left out if you are not calling this function from a package.

.. and attaching it to a page

$feedTypeAttributeKey = CollectionAttributeKey::getByHandle('attribute_handle');
if (!is_object(SelectAttributeTypeOption::getByValue('Your Attribute Name', $feedTypeAttributeKey))) {
    // I really cannot remember why 4 arguments, as looking into the source it appears this fn takes 3 :S
    SelectAttributeTypeOption::add($feedTypeAttributeKey, 'Your Attribute Name', 0, 0);  
$newPage->setAttribute('attribute_handle', 'Your Attribute Name');

Creating users

$email = '';
$ui = UserInfo::getByEmail($email);

if (!is_null($ui)) {
    // Email is already in use, so let's not create the user

$userData['uName'] = 'username';
$userData['uEmail'] = $email;
$userData['uPassword'] = 'password';
$userData['uPasswordConfirm'] = 'password';

$ui = UserInfo::register($userData);

Adding or removing users from group

$u = $ui->getUserObject();
$g = Group::getByName('Group Name');


 Creating user attributes and attaching them

$ak = UserAttributeKey::getByHandle('your_attribute_handle');
if(!is_object($ak)) {
        array('akHandle' => 'your_attribute_handle', 'akName' => t('Some attribute name'), 'akIsSearchable' => true), $this

$ui->setAttribute("your_attribute_handle", "Some attribute value");


Indrek Kõnnussaar

I'm a veteran Wordpress developer, context-driven tester, security enthusiast and the mastermind behind Codelight. I love building stuff that works and fixing stuff that doesn't.

Write me directly

3 Responses to “Programmatically creating attributes, objects etc in Concrete5”

  1. Warren

    How do you programmatically add options to a select attribute ?

    • Indrek Kõnnussaar

      Sorry, haven’t used Concrete5 for a very long time so I can’t help you.

      Also, considering the fact that it’s 2016 and it’s *still* not very easy to find this relatively basic information regarding their API, I would really recommend moving to another CMS. Just my .02€, though.

    • Annie

      $pulln = AttributeType::getByHandle(‘select’);
      if( !is_object($category) ) {
      array(‘akHandle’ => ‘category’,
      ‘akName’ => t(‘Publishing Category’),
      ‘akIsSearchable’ => false,
      ‘akSelectAllowMultipleValues’ => true,

      $myAttribute = CollectionAttributeKey::getByHandle(‘category’);
      SelectAttributeTypeOption::add( $myAttribute, ‘Daily’);
      SelectAttributeTypeOption::add( $myAttribute, ‘Weekly’);
      SelectAttributeTypeOption::add( $myAttribute, ‘Monthly’);
      SelectAttributeTypeOption::add( $myAttribute, ‘Yearly’);


Leave a Reply

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now