1

I am struggling to create a new category group and category programmatically. I've found a few examples for creating an entry, and one for creating categories in Craft 2, but I can't get it working in Craft 4. Here's my attempt at creating a new category group and related category within a content migration:

use \craft\elements\Category;
use \craft\models\CategoryGroup;
use \craft\models\CategoryGroup_SiteSettings;

[...]

$defaultSite = Craft::$app->sites->getSiteByHandle('default');

Craft::$app->categories->saveGroup(new CategoryGroup([
    'name' => 'My Category Group',
    'handle' => 'myCategoryGroup',
    'maxLevels' => 1,
    'defaultPlacement' => 'end',
    'siteSettings' => [new CategoryGroup_SiteSettings([
        'siteId' => $defaultSite->id,
        'uriFormat' => 'categories/{slug}',
        'template' => 'myTemplate',
    ])],
]));
// -> Exception: Tried to save a category group that is missing site settings

$myCategoryGroup = Craft::$app->categories->getGroupByHandle('myCategoryGroup');

Craft::$app->getElements()->saveElement(new Category([
    'title' => 'My Category',
    'slug' => 'my-category',
    'enabled' => true,
    'siteId' => $defaultSite->id,
    'groupId' => $myCategoryGroup->id,
]));

Is there a guide or some examples for doing this? Please help.

1 Answer 1

2

This works:

UPDATE: As @MatsMikkelRummelhoff has pointed out, Craft's project config will handle the schema for category groups.

$defaultSite = Craft::$app->sites->getSiteByHandle('default');

// Create category group
// UPDATE: Craft's project config will actually handle the category groups; better to allow it to do so
Craft::$app->categories->saveGroup(new CategoryGroup([
    'name' => 'My Category Group',
    'handle' => 'myCategoryGroup',
    'maxLevels' => 1,
    'siteSettings' => [$defaultSite->id => new CategoryGroup_SiteSettings([
        'hasUrls' => true,
        'uriFormat' => 'categories/{slug}',
        'template' => 'myTemplate',
    ])],
]));

$categoryGroup = Craft::$app->categories->getGroupByHandle('articleCategories');

// Create category within group
Craft::$app->getElements()->saveElement(new Category([
    'title' => 'My Category',
    'slug' => 'my category',
    'enabled' => true,
    'siteId' => $defaultSite->id,
    'groupId' => $categoryGroup->id,
]));

Two things:

  1. It seems that when creating a category group, the siteSettings property needs to be an associative array with the key(s) corresponding to the site ID for which it applies. This is not clear from the API documentation.
  2. Furthermore, I was running this code with the safeUp() method of a migration and wasn't returning true, therefore everything was being rolled back.

Nonetheless, I would welcome any comments about a better way to learn how to programmatically create different content elements (other than wading through the API documentation and fiddling with things until they work).

2
  • 2
    Also, be aware that category groups is schema and not content – and as such Craft will write to the project config when the groups are added. If the project is tracking schema changes by having the project config YAML files in version control, you should be careful that the code adding the groups isn't run in production (i.e. any environment that has the allowAdminChanges config setting set to false). Commented Nov 12, 2022 at 14:52
  • @MatsMikkelRummelhoff you're right. I expected category groups to be handled by project config, but for some reason I did not see the changes reflected in mine so I thought Craft was treating them like content. It's much better/easier to let the project config handle the groups.
    – Garrett
    Commented Nov 14, 2022 at 20:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.