{"id":19110167,"url":"https://github.com/locomotivemtl/charcoal-cms","last_synced_at":"2025-08-21T01:32:15.252Z","repository":{"id":29165427,"uuid":"32695942","full_name":"locomotivemtl/charcoal-cms","owner":"locomotivemtl","description":"Charcoal Content Management System (CMS) Module","archived":false,"fork":false,"pushed_at":"2025-06-18T20:48:35.000Z","size":16695,"stargazers_count":52,"open_issues_count":3,"forks_count":6,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-07-31T09:07:04.144Z","etag":null,"topics":["charcoal","cms","content-management-system","php"],"latest_commit_sha":null,"homepage":"http://charcoal.locomotive.ca","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/locomotivemtl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-03-22T21:16:14.000Z","updated_at":"2025-07-07T12:48:05.000Z","dependencies_parsed_at":"2024-06-19T03:53:04.834Z","dependency_job_id":"231f0a24-f94f-43d9-8d68-47db6f76c9fe","html_url":"https://github.com/locomotivemtl/charcoal-cms","commit_stats":{"total_commits":332,"total_committers":13,"mean_commits":25.53846153846154,"dds":0.7168674698795181,"last_synced_commit":"9490ca3ad1725555565a535b76e873d2bb34ac57"},"previous_names":[],"tags_count":68,"template":false,"template_full_name":null,"purl":"pkg:github/locomotivemtl/charcoal-cms","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locomotivemtl%2Fcharcoal-cms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locomotivemtl%2Fcharcoal-cms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locomotivemtl%2Fcharcoal-cms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locomotivemtl%2Fcharcoal-cms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/locomotivemtl","download_url":"https://codeload.github.com/locomotivemtl/charcoal-cms/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/locomotivemtl%2Fcharcoal-cms/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271415031,"owners_count":24755628,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-20T02:00:09.606Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["charcoal","cms","content-management-system","php"],"created_at":"2024-11-09T04:23:54.384Z","updated_at":"2025-08-21T01:32:14.878Z","avatar_url":"https://github.com/locomotivemtl.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Charcoal CMS\n============\n\nThe CMS Charcoal Module (_Content Management System_). Provides basic objects to build a website.\nNotably, `Section` (or _page_), `News`, `Event` and `Faq` as well as to ather user data, notably `ContactInquiry`.\n\nThis module is heavily dependant on [`charcoal-object`](https://github.com/locomotivemtl/charcoal-object) (and therefore `charcoal-core`) which provides the base `Content` class the CMS objects are dependant on, as well as many trait / interface behaviors.\n\n# How to install\n\nThe preferred (and only supported) way of installing _charcoal-cms_ is with **composer**:\n\n```shell\n★ composer require locomotivemtl/charcoal-cms\n```\n\nFor a complete, ready-to-use project, start from the [`charcoal project boilerplate`](https://github.com/locomotivemtl/charcoal-project-boilerplate):\n\n```shell\n★ composer create-project locomotivemtl/charcoal-project-boilerplate:@dev --prefer-source\n```\n\n## Dependencies\n\n-   [`PHP 5.6+`](http://php.net)\n    - PHP 7 is recommended for security and performance reasons.\n-   [`locomotivemtl/charcoal-attachment`](https://github.com/locomotivemtl/charcoal-attachment)\n    - Content blocks are provided with _attachments_.\n-   [`locomotivemtl/charcoal-core`](https://github.com/locomotivemtl/charcoal-core)\n    - Core charcoal models and storage class.\n    - Provides base Model, which depends on Storable and Describable.\n-   [`locomotivemtl/charcoal-object`](https://github.com/locomotivemtl/charcoal-object)\n    - CMS objects are based on `\\Charcoal\\Object\\Content`.\n-   [`locomotivemtl/charcoal-translator`](https://github.com/locomotivemtl/charcoal-translator)\n    - Localization is provided by symfony translator (charcoal).\n\n### Recommended dependencies\n\n-   [`locomotivemtl/charcoal-admin`](https://github.com/locomotivemtl/charcoal-admin)\n    - The backend (admin panel).\n\n# Objects\n\n-   **Core objects**\n    -   [Section](#section-object)\n    -   [Tag](#tag-object)\n-   **CMS objects**\n    -   [Event](#event-object)\n    -   [FAQ](#faq-object)\n    -   [News](#news-object)\n\n# Core objects\n\n-   [Section](#section-object)\n-   [Tag](#tag-object)\n\n## Section object\n\nA **section**, in Charcoal, is a reachable _page_ on the website, as part of the full hierarchical site map. They can be displayed in menus or breadcrumbs and be reached with a unique URL (`routable`).\n\nTypes of sections:\n\n-   `blocks`\n    -   Blocks sections define their content as a structured map of blocks.\n-   `content`\n    -   Content sections define their content in a single, simple _HTML_ property.\n-   `empty`\n    -   Empty sections are linked to a template but do not require any custom content.\n-   `external`\n    -   External sections are simply a redirect to an external (or internal) URL.\n\nAll section types, except _external_, make use of a `Template` object to be rendered. Typically, a charcoal `view` make sure of linking the `template` (by default, _mustache_\n\n\u003e Sections are standard Charcoal `Model`, meaning they are _describable_ with a `Metadata` object (which define a map of `properties`) and _storable_ with a `Source` object.\n\nBase section properties:\n\n| Interface     | Name                 | L10n | Type      | Description |\n| ------------- | -------------------- | :--: | --------- | ----------- |\n| Section       | **section_type**     |      | choice    |\n| Section       | **title**            | ✔    | string    |\n| Section       | **subtitle**         | ✔    | html      |\n| Section       | **summary**          | ✔    | html      |\n| Section       | **image**            | ✔    | image     |\n| Section       | **template_ident**    |      | string    |\n| Section       | **template_options**  |      | structure |\n| Section       | **content**           | ✔    | html      |\n| Section       | **attachments**       | ✔    | multi-object |\n| Section       | **external_url**      | ✔    | url       | For external URLs. Note that all content-related properties are ignored if this property is set. |\n| Content       | **id**                |      | id        | The model's `key`. |\n| Content       | **active**            |      | bool      | Inactive events should not appear in public API / frontend. |\n| Content       | **position**          |      | int       | Default order property. |\n| Authorable    | **created_by**        |      | string    | Admin user.\n| Authorable    | **last\\_modified_by** |      | string    | Admin user.\n| Authorable    | **required\\_acl_permissions** | array    | To do...\n| Timestampable | **created**           |      | date-time |\n| Timestampable | **last_modified**     |      | date-time |\n| Hierarchical  | **master**            |      | object | `SectionInterface`. |\n| Routable      | **slug**              | ✔    | string | Permalink. Auto-generated from title. |\n\n### Interfaces\n\nFrom model:\n\n- `Describable`: The objects can be defined by Metadata.\n- `Storable`: Objects have unique IDs and can be stored in storage / database.\n\nFrom content:\n\n- `Content`: A \"managed\" charcoal model (describable with metadata / storable).\n- `Authorable`: Creation and modification user (admin) are kept in the storage.\n- `Revisionable`: Copy of changes will be kept upon each object update in the storage.\n- `Timestampable`: Creation and modification time are kept into the storage.\n\nFrom charcoal-object\n\n- `Hierarchicale`: The objects can be stacked hierarchically.\n- ~~`Publishable`: Objects have publish status, date and expiry. Allows moderation.~~\n- `Routable`: Objects are reachable through a URL.\n\nFrom charcoal-cms:\n\n- `Metatag`: The objects have meta-information for SEO purpose.\n- `Searchable`: Extra keywords can be used to help search engine.\n- `Templateable`: The objects can be rendered with a template / controller / config combo.\n\n### Extending the section object\n\nThe `\\Charcoal\\Cms\\Section\\*` objects are `final`. To extend, use the `\\Charcoal\\Cms\\AbstractSection` base object instead, to make sure no metadata conflicts arise.\n\n## Tag object\n\n**Tag** objects link any objects together by providing an extra taxonomy layer. Tags may also be used to enhance internal search engines.\n\n# CMS objects\n\n-   [Event](#event-object)\n-   [FAQ](#faq-object)\n-   [News](#news-object)\n\n## Event object\n\nCharcoal **Event** is a specialized content object to describe an event, which typically happens at a given date in a certain location.\n\nBase events properties:\n\n| Interface     | Name                  | L10n | Type      | Description |\n| ------------- | --------------------- | :--: | --------- | ----------- |\n| Event         | **title**             | ✔    | string    |\n| Event         | **subtitle**          | ✔    | html      |\n| Event         | **summary**           | ✔    | html      |\n| Event         | **content**           | ✔    | html      |\n| Event         | **image**             | ✔    | image     |\n| Event         | **start_date**        |      | date-time |\n| Event         | **end_date**          |      | date-time |\n| Event         | **info_url**          | ✔    | image     |\n| Content       | **id**                |      | id        | The model's `key`. |\n| Content       | **active**            |      | bool      | Inactive events should not appear in public API / frontend. |\n| Content       | **position**          |      | int       | Default order property. |\n| Authorable    | **created_by**        |      | string    | Admin user.\n| Authorable    | **last\\_modified_by** |      | string    | Admin user.\n| Authorable    | **required\\_acl_permissions** | array    | To do...\n| Timestampable | **created**           |      | date-time |\n| Timestampable | **last_modified**     |      | date-time |\n| Categorizable | **category**          | ✔    | object    | `EventCategory`, or custom. |\n| Publishable   | **publishDate**      |      | date-time |\n| Publishable   | **expiryDate**       |      | date-time |\n| Publishable   | **publishStatus**    |      | string    | `draft`, `pending`, or `published`. |\n| Routable      | **slug**              | ✔    | string    | Permalink. Auto-generated from title. |\n| Metatag       | **meta_title**       | ✔    | string    |\n| Metatag       | **meta_description** | ✔    | string    |\n| Metatag       | **meta_image**       | ✔    | image     |\n| Metatag       | **meta_author**      | ✔    | string    |\n| Templateable  | **controller_ident** |      | string    |\n| Templateable  | **template_ident**   |      | string    |\n| Templateable  | **template_options** |      | structure |\n\n### Interfaces\n\nFrom model:\n\n- `Describable`: The objects can be defined by Metadata.\n- `Storable`: Objects have unique IDs and can be stored in storage / database.\n\nFrom content:\n\n- `Content`: A \"managed\" charcoal model (describable with metadata / storable).\n- `Authorable`: Creation and modification user (admin) are kept in the storage.\n- `Revisionable`: Copy of changes will be kept upon each object update in the storage.\n- `Timestampable`: Creation and modification time are kept into the storage.\n\nFrom charcoal-object:\n\n- `Categorizable`: The objects can be put into a category.\n- `Publishable`: Objects have publish status, date and expiry. Allows moderation.\n- `Routable`: Objects are reachable through a URL.\n\nFrom charcoal-cms:\n\n- `Metatag`: The objects have meta-information for SEO purpose.\n- `Searchable`: Extra keywords can be used to help search engine.\n- `Templateable`: The objects can be rendered with a template / controller / config combo.\n\n### Extending the event object\n\nThe `\\Charcoal\\Cms\\Event` object is `final`. To extend, use the `\\Charcoal\\Cms\\AbstractEvent` base object instead, to make sure no metadata conflicts arise.\n\n### Event categories\n\n**Event category** objects are simple `charcoal/object/category` used to group / categorize events. The default type is `Charcoal\\Cms\\EventCategory`.\n\n_Events_ implement the `Categorizable` interface, from charcoal-object.\n\n## FAQ object\n\n**FAQ** objects are a special content type that is split in a \"question\" / \"answer\" format.\n\n### FAQ categories\n\n**FAQ category** objects are simple `charcoal/object/category` used to group / categorize FAQ objects. The default type is `Charcoal\\Cms\\FaqCategory`.\n\n_FAQs_ implement the `Categorizable` interface, from charcoal-object.\n\n## News object\n\nNews object are a special content type that with a specific news date.\n\nBase news properties:\n\n| Interface     | Name                  | L10n | Type      | Description |\n| ------------- | --------------------- | :--: | --------- | ----------- |\n| News          | **title**             | ✔    | string    |\n| News          | **subtitle**          | ✔    | html      |\n| News          | **summary**           | ✔    | html      |\n| News          | **content**           | ✔    | html      |\n| News          | **image**             | ✔    | image     |\n| News          | **news_date**         |      | date-time |\n| News          | **info_url**          | ✔    | image     |\n| Content       | **id**                |      | id        | The model's `key`. |\n| Content       | **active**            |      | bool      | Inactive news should not appear in public API / frontend. |\n| Content       | **position**          |      | int       | Default order property. |\n| Authorable    | **created_by**        |      | string    | Admin user.\n| Authorable    | **last\\_modified_by** |      | string    | Admin user.\n| Authorable    | **required\\_acl_permissions** | array    | To do...\n| Timestampable | **created**           |      | date-time |\n| Timestampable | **last_modified**     |      | date-time |\n| Categorizable | **category**          | ✔    | object    | `NewsCategory`, or custom. |\n| Publishable   | **publishDate**      |      | date-time |\n| Publishable   | **expiryDate**       |      | date-time |\n| Publishable   | **publishStatus**    |      | string    | `draft`, `pending`, or `published`. |\n| Routable      | **slug**              | ✔    | string    | Permalink. Auto-generated from title. |\n| Metatag       | **meta_title**       | ✔    | string    |\n| Metatag       | **meta_description** | ✔    | string    |\n| Metatag       | **meta_image**       | ✔    | image     |\n| Metatag       | **meta_author**      | ✔    | string    |\n| Templateable  | **controller_ident** |      | string    |\n| Templateable  | **template_ident**   |      | string    |\n| Templateable  | **template_options** |      | structure |\n\n### Interfaces\n\nFrom model:\n\n- `Describable`: The objects can be defined by Metadata.\n- `Storable`: Objects have unique IDs and can be stored in storage / database.\n\nFrom content:\n\n- `Content`: A \"managed\" charcoal model (describable with metadata / storable).\n- `Authorable`: Creation and modification user (admin) are kept in the storage.\n- `Revisionable`: Copy of changes will be kept upon each object update in the storage.\n- `Timestampable`: Creation and modification time are kept into the storage.\n\nFrom charcoal-object:\n\n- `Categorizable`: The objects can be put into a category.\n- `Publishable`: Objects have publish status, date and expiry. Allows moderation.\n- `Routable`: Objects are reachable through a URL.\n\nFrom charcoal-cms:\n\n- `Metatag`: The objects have meta-information for SEO purpose.\n- `Searchable`: Extra keywords can be used to help search engine.\n- `Templateable`: The objects can be rendered with a template / controller / config combo.\n\n### Extending the news object\n\nThe `\\Charcoal\\Cms\\News` object is `final`. To extend, use the `\\Charcoal\\Cms\\AbstractNews` base object instead, to make sure no metadata conflicts arise.\n\n### News categories\n\n**News category** objects are simple `charcoal/object/category` used to group / categorize events. The default type is `Charcoal\\Cms\\NewsCategory`.\n\n_News_ implement the `Categorizable` interface, from charcoal-object.\n\n# Development\n\nTo install the development environment:\n\n```shell\n$ composer install --prefer-source\n```\n\n## API documentation\n-   The auto-generated `phpDocumentor` API documentation is available at [https://locomotivemtl.github.io/charcoal-cms/docs/master/](https://locomotivemtl.github.io/charcoal-cms/docs/master/)\n-   The auto-generated `apigen` API documentation is available at [https://codedoc.pub/locomotivemtl/charcoal-cms/master/](https://codedoc.pub/locomotivemtl/charcoal-cms/master/index.html)\n\n## Development dependencies\n\n-   `phpunit/phpunit`\n-   `squizlabs/php_codesniffer`\n-   `satooshi/php-coveralls`\n\n## Continuous Integration\n\n| Service | Badge | Description |\n| ------- | ----- | ----------- |\n| [Travis](https://travis-ci.org/locomotivemtl/charcoal-cms) | [![Build Status](https://travis-ci.org/locomotivemtl/charcoal-cms.svg?branch=master)](https://travis-ci.org/locomotivemtl/charcoal-cms) | Runs code sniff check and unit tests. Auto-generates API documentation. |\n| [Scrutinizer](https://scrutinizer-ci.com/g/locomotivemtl/charcoal-cms/) | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/locomotivemtl/charcoal-cms/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/locomotivemtl/charcoal-cms/?branch=master) | Code quality checker. Also validates API documentation quality. |\n| [Coveralls](https://coveralls.io/github/locomotivemtl/charcoal-cms) | [![Coverage Status](https://coveralls.io/repos/github/locomotivemtl/charcoal-cms/badge.svg?branch=master)](https://coveralls.io/github/locomotivemtl/charcoal-cms?branch=master) | Unit Tests code coverage. |\n| [Sensiolabs](https://insight.sensiolabs.com/projects/533b5796-7e69-42a7-a046-71342146308a) | [![SensioLabsInsight](https://insight.sensiolabs.com/projects/44d8d264-207b-417d-bcbd-dd52274fc201/mini.png)](https://insight.sensiolabs.com/projects/44d8d264-207b-417d-bcbd-dd52274fc201) | Another code quality checker, focused on PHP. |\n\n## Coding Style\n\nThe `charcoal-cms` module follows the Charcoal coding-style:\n\n-   [_PSR-1_](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md)\n-   [_PSR-2_](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)\n-   [_PSR-4_](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md), autoloading is therefore provided by _Composer_.\n-   [_phpDocumentor_](http://phpdoc.org/) comments.\n-   Read the [phpcs.xml](phpcs.xml) file for all the details on code style.\n\n\u003e Coding style validation / enforcement can be performed with `composer phpcs`. An auto-fixer is also available with `composer phpcbf`.\n\n# Authors\n\n-   [Locomotive](https://locomotive.ca)\n\n# License\n\nCharcoal is licensed under the MIT license. See [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocomotivemtl%2Fcharcoal-cms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flocomotivemtl%2Fcharcoal-cms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocomotivemtl%2Fcharcoal-cms/lists"}