craftcms/cms
Craft CMS is a flexible, user-friendly PHP CMS for building custom web experiences. Features a Twig templating system, auto-generated GraphQL API for headless builds, ecommerce via Craft Commerce, a plugin store, and a powerful extension framework.
Installation
composer require craftcms/cms
First Use Case: Creating a Basic Entry
Settings > Sections).templates/_entry.twig to render entries:
{% extends "_layouts/base" %}
{% block content %}
<h1>{{ entry.title }}</h1>
{{ entry.body }}
{% endblock %}
{% set entries = craft.entries.section('blog').all() %}
{% for entry in entries %}
{{ entry.title }}
{% endfor %}
Key First Look
http://your-site.com/admin to manage content.config/app.php to inspect variables:
'devMode' => true,
PlainText, Matrix, Assets) or create custom fields via plugins.
// Example: Adding a custom field to an entry type
Event::on(
EntryType::class,
EntryType::EVENT_DEFINE_FIELDS,
function (DefineFieldsEvent $event) {
$event->fields['customField'] = Field::make('plainText')
->label('Custom Field');
}
);
Channel, Single, Structure).// config/app.php
'components' => [
'view' => [
'twig' => [
'extension' => [
\App\Twig\CustomExtension::class,
],
],
],
];
// App/Twig/CustomExtension.php
class CustomExtension extends \Twig\Extension\AbstractExtension
{
public function getFunctions()
{
return [
new \Twig\TwigFunction('customFunction', [$this, 'customFunction']),
];
}
public function customFunction($arg)
{
return "Processed: " . $arg;
}
}
_layouts/ for shared layouts and _includes/ for reusable components.with and relations:
{% set entry = craft.entries()
.section('blog')
.title('First Post')
.with(['author', 'categories'])
.one() %}
$entries = Entry::find()
->section('blog')
->postDate('>= ' . date('Y-m-d'))
->orderBy(['postDate' => SORT_DESC])
->all();
config/app.php:
'enableGraphQl' => true,
query {
entries(section: "blog") {
title
body
author {
name
}
}
}
php craft create-plugin MyPlugin
MyPlugin.php.{% set image = entry.heroImage.one() %}
<img src="{{ image.getUrl('thumb') }}" alt="{{ image.title }}">
Settings > Assets.config/sites.php.craft i18n for content translations.// config/routes.php
return [
'api/v1/entries' => \App\controllers\EntriesController::class,
];
Laravel Integration
vendor/ directory.web.php.Route::get('/api/craft/{path}', function ($path) {
return app('craft')->getRequest()->setPathInfo('/api/' . $path)->run();
});
Queue System
php craft queue/run
class MyJob extends \craft\queue\BaseJob
{
public function execute($queue)
{
// Task logic
}
}
Security
Settings > Users > Permissions).craft\helpers\Html::encode().Performance
craft.app.cache:
$cache = Craft::$app->getCache();
$cache->set('key', 'value', 3600);
'assetIndexingEnabled' => false,
Runtime Path Issues
runtimePath in config/app.php may not work due to #18936.'runtimePath' => __DIR__ . '/../runtime',
Entry Post Dates
null until the entry is saved as enabled (#18642).$entry->postDate = time();
Matrix Field Quirks
uiLabel in the entry type settings.GraphQL Sandboxing
dataUrl() is disabled by default in sandboxed environments.config/graphql.php:
'sandboxed' => [
'allowedFunctions' => ['dataUrl'],
],
Element Deletion
if ($element->getContent()->getRelations()) {
Craft::$app->getSession()->setErrorCms('Element has dependencies.');
}
Twig Debugging
{{ dump() }} may not work in production due to devMode.{{ craft.app.config.devMode ? dump(_context) : '' }} or enable debug toolbar.Asset Alternative Text
$asset->alternativeText = $oldAsset->alternativeText;
Element Indexes
.element-index {
overflow-x: hidden !important;
}
How can I help you explore Laravel packages today?