{"id":18147272,"url":"https://github.com/paranoid-software/elemental-cms","last_synced_at":"2026-04-02T22:40:21.277Z","repository":{"id":40130429,"uuid":"431239997","full_name":"paranoid-software/elemental-cms","owner":"paranoid-software","description":"Flask + MongoDB web CMS","archived":false,"fork":false,"pushed_at":"2024-09-04T20:44:25.000Z","size":385,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-16T01:12:44.883Z","etag":null,"topics":["cms","flask","mongodb","python","web"],"latest_commit_sha":null,"homepage":"https://paranoid.software/elemental-cms","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paranoid-software.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"patreon":"paranoidsoftware","ko_fi":"paranoidsoftware"}},"created_at":"2021-11-23T20:12:44.000Z","updated_at":"2024-09-04T20:43:29.000Z","dependencies_parsed_at":"2023-11-12T12:27:17.006Z","dependency_job_id":"a96f4110-0991-4b24-95a2-deda2bfa5290","html_url":"https://github.com/paranoid-software/elemental-cms","commit_stats":{"total_commits":155,"total_committers":3,"mean_commits":"51.666666666666664","dds":"0.14193548387096777","last_synced_commit":"b718858593c0cacd0fc6fd137ae1e0754666d283"},"previous_names":[],"tags_count":66,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paranoid-software%2Felemental-cms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paranoid-software%2Felemental-cms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paranoid-software%2Felemental-cms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paranoid-software%2Felemental-cms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paranoid-software","download_url":"https://codeload.github.com/paranoid-software/elemental-cms/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250522293,"owners_count":21444510,"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","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":["cms","flask","mongodb","python","web"],"created_at":"2024-11-01T22:06:10.789Z","updated_at":"2026-03-11T18:35:36.929Z","avatar_url":"https://github.com/paranoid-software.png","language":"Python","funding_links":["https://patreon.com/paranoidsoftware","https://ko-fi.com/paranoidsoftware"],"categories":[],"sub_categories":[],"readme":"# elemental CMS\n\nElemental is a Flask and MongoDB web CMS intended for developers.\n\nOur main goal is to allow developers to create and maintain web portals or web applications using their preferred programming IDE like VS Code, PyCharm, Visual Studio, etc.\n\nThe main interaction with the tool takes place through its CLI, a self documented command line tool called \"elemental-cms\" which helps us perform deployment tasks directly from the terminal.\n\nIt relies on MongoDB to store the metadata, pages' content, snippets' content, dependencies information, and user session data.\n\n## Version Compatibility\n\nElemental CMS 2.0.6 is compatible with:\n- Flask 2.2.5\n- Werkzeug 2.2.3\n- Flask-Babel 2.0.0\n- Python 3.6+\n\nFor version history and changes, see our [CHANGELOG](CHANGELOG.md).\n\n## Work in progress\n\n- \u003ca href=\"https://paranoid.software/en/elemental-cms/docs\" target=\"_blank\"\u003eOfficial documentation\u003c/a\u003e construction\n- Media files management on GCS module test classes\n- Static files management on GCS module test classes\n- Samples review and update\n\n## To Do\n\n- Resources names validation for pages (similar to snippets)\n- Configurations schema review\n- Test coverage review\n- Support for sample settings file generation\n\n## Configuration Guide\n\nElemental CMS uses a JSON configuration file that defines how the CMS operates. There are two main contexts:\n\n### Core Context (`cmsCoreContext`)\n\n#### Basic Settings\n- `DEBUG`: Enable/disable debug mode (default: false)\n- `ENV`: Environment name (e.g., \"development\", \"production\")\n- `SECRET_KEY`: Flask secret key for session encryption\n- `SITE_NAME`: Your site's name, used in templates\n- `COMPANY`: Your company name\n- `CANONICAL_URL`: Base URL for your site\n\n#### Language Settings\n- `LANGUAGES`: List of supported language codes (e.g., [\"en\", \"es\"])\n- `DEFAULT_LANGUAGE`: Default language code (e.g., \"en\")\n- `LANGUAGE_MODE`: Either \"single\" or \"multi\" for language handling\n  - \"single\": No language prefixes in URLs\n  - \"multi\": URLs prefixed with language code (e.g., /en/about)\n\n#### File Storage Settings\n- `STATIC_FOLDER`: Local folder for static files (default: \"static\")\n- `MEDIA_FOLDER`: Local folder for media files (default: \"media\")\n- `STATIC_URL`: URL for static files\n  - Local: \"/static\"\n  - Cloud: \"https://storage.googleapis.com/your-bucket\"\n- `MEDIA_URL`: URL for media files\n  - Local: \"/media\"\n  - Cloud: \"https://storage.googleapis.com/your-bucket\"\n\n#### Cloud Storage (Optional)\n- `STATIC_BUCKET`: GCS bucket name for static files\n- `MEDIA_BUCKET`: GCS bucket name for media files\n- `GOOGLE_SERVICE_ACCOUNT_INFO`: GCS service account credentials\n  - Required only when using Google Cloud Storage\n  - Used by CLI for file operations\n\n#### Workspace Settings\n- `GLOBAL_DEPS_FOLDER`: Folder for global dependencies (default: \"workspace/global_deps\")\n- `PAGES_FOLDER`: Folder for page files (default: \"workspace/pages\")\n- `SNIPPETS_FOLDER`: Folder for snippet files (default: \"workspace/snippets\")\n\n#### Session Settings\n- `USER_IDENTITY_SESSION_KEY`: Session key for user identity (default: \"userIdentity\")\n- `SESSION_STORAGE_ENABLED`: Enable MongoDB session storage (default: true)\n- `SESSION_TIMEOUT_IN_MINUTES`: Session timeout in minutes (default: 360)\n\n#### Development Settings\n- `DESIGN_MODE_ENABLED`: Enable local file-based content editing (default: false)\n  - When true: Content is read from local files\n  - When false: Content is read from MongoDB\n\n### Database Context (`cmsDbContext`)\n- `id`: Unique identifier for your MongoDB connection\n- `connectionString`: MongoDB connection string\n  - Format: \"mongodb://username:password@hostname:port/admin?directConnection=true\"\n- `databaseName`: Name of the MongoDB database to use\n\n### Understanding CLI vs Web App Settings\n\nElemental CMS uses two separate configuration files:\n\n1. **CLI Settings** (`local.cli.json`):\n   - Used by the `elemental-cms` command-line tool\n   - Requires cloud storage configuration (`STATIC_BUCKET`, `MEDIA_BUCKET`, `GOOGLE_SERVICE_ACCOUNT_INFO`)\n   - Used for content management operations (push, pull, publish)\n   - Example operations that use CLI settings:\n     ```shell\n     elemental-cms init -c settings/local.cli.json\n     elemental-cms pages push -p home en\n     elemental-cms media push image.jpg\n     ```\n\n2. **Web App Settings** (`local.www.json`):\n   - Used by your Flask web application\n   - Focuses on serving content and handling requests\n   - Does not need cloud storage credentials\n   - Used when running your web application\n   - Example usage:\n     ```python\n     CONFIG_FILEPATH = os.environ.get('CONFIG_FILEPATH', 'settings/local.www.json')\n     ```\n\n#### Key Differences:\n\n| Setting | CLI Config | Web App Config | Notes |\n|---------|------------|----------------|-------|\n| `STATIC_BUCKET` | Required | Optional | CLI needs it for push/pull operations |\n| `MEDIA_BUCKET` | Required | Optional | CLI needs it for media management |\n| `GOOGLE_SERVICE_ACCOUNT_INFO` | Required | Not needed | Only CLI performs cloud operations |\n| `STATIC_URL` | Cloud URL | Can be local | Web app can serve files locally |\n| `MEDIA_URL` | Cloud URL | Can be local | Web app can serve files locally |\n| `DESIGN_MODE_ENABLED` | Not used | Optional | Only affects web app behavior |\n\n#### Example Workflow:\n1. Use CLI config (`local.cli.json`) to manage content:\n   ```shell\n   # Push content to cloud storage\n   elemental-cms push --all\n   ```\n\n2. Use Web config (`local.www.json`) to serve content:\n   ```python\n   # Web app serves content from local or cloud\n   Elemental(www, elemental_context)\n   ```\n\n### Configuration Examples\n\n#### Local Development\n\nCLI Config (`local.cli.json`):\n```json\n{\n  \"cmsCoreContext\": {\n    \"DEBUG\": true,\n    \"ENV\": \"development\",\n    \"STATIC_URL\": \"https://storage.googleapis.com/static-bucket\",\n    \"MEDIA_URL\": \"https://storage.googleapis.com/media-bucket\",\n    \"STATIC_BUCKET\": \"static-bucket\",\n    \"MEDIA_BUCKET\": \"media-bucket\",\n    \"GOOGLE_SERVICE_ACCOUNT_INFO\": {\n      \"type\": \"service_account\",\n      \"project_id\": \"your-project\"\n    },\n    \"DESIGN_MODE_ENABLED\": false\n  }\n}\n```\n\nWeb App Config (`local.www.json`):\n```json\n{\n  \"cmsCoreContext\": {\n    \"DEBUG\": true,\n    \"ENV\": \"development\",\n    \"STATIC_URL\": \"/static\",\n    \"MEDIA_URL\": \"/media\",\n    \"DESIGN_MODE_ENABLED\": true\n  }\n}\n```\n\n#### Production Environment\n\nCLI Config (`production.cli.json`):\n```json\n{\n  \"cmsCoreContext\": {\n    \"DEBUG\": false,\n    \"ENV\": \"production\",\n    \"STATIC_URL\": \"https://storage.googleapis.com/static-bucket\",\n    \"MEDIA_URL\": \"https://storage.googleapis.com/media-bucket\",\n    \"STATIC_BUCKET\": \"static-bucket\",\n    \"MEDIA_BUCKET\": \"media-bucket\",\n    \"GOOGLE_SERVICE_ACCOUNT_INFO\": {\n      \"type\": \"service_account\",\n      \"project_id\": \"your-project\"\n    }\n  }\n}\n```\n\nWeb App Config (`production.www.json`):\n```json\n{\n  \"cmsCoreContext\": {\n    \"DEBUG\": false,\n    \"ENV\": \"production\",\n    \"STATIC_URL\": \"https://storage.googleapis.com/static-bucket\",\n    \"MEDIA_URL\": \"https://storage.googleapis.com/media-bucket\",\n    \"DESIGN_MODE_ENABLED\": false\n  }\n}\n```\n\n## Setup \u003ca id=\"setup\"\u003e#\u003c/a\u003e\n\nOnce we have our project folder created and our virtual environment in place, we proceed to install Elemental CMS using pip.\n\n```shell\npip install elemental-cms\n```\n\nThe CLI includes an \"init\" command which will create a basic working directory structure.\n\nBefore we can issue the \"init\" command, we have to create a config file inside a \"settings\" folder with at least the following content:\n\n```json\n{\n  \"cmsCoreContext\": {\n    \"DEBUG\": true,\n    \"ENV\": \"development\",\n    \"SECRET_KEY\": \"the-secret\",\n    \"SITE_NAME\": \"Elemental CMS\",\n    \"COMPANY\": \"Your company name\",\n    \"CANONICAL_URL\": \"https://elemental.cms\",\n    \"LANGUAGES\": [\n      \"en\",\n      \"es\"\n    ],\n    \"DEFAULT_LANGUAGE\": \"en\",\n    \"LANGUAGE_MODE\": \"multi\",\n    \"STATIC_FOLDER\": \"static\",\n    \"MEDIA_FOLDER\": \"media\",\n    \"STATIC_URL\": \"https://storage.googleapis.com/static-files-bucket\",\n    \"MEDIA_URL\": \"https://storage.googleapis.com/media-files-bucket\",\n    \"STATIC_BUCKET\": \"static-files-bucket\",\n    \"MEDIA_BUCKET\": \"media-files-bucket\",\n    \"GLOBAL_DEPS_FOLDER\": \"workspace/global_deps\",\n    \"PAGES_FOLDER\": \"workspace/pages\",\n    \"SNIPPETS_FOLDER\": \"workspace/snippets\",\n    \"GOOGLE_SERVICE_ACCOUNT_INFO\": {\n      \"type\": \"service_account\",\n    },\n    \"USER_IDENTITY_SESSION_KEY\": \"userIdentity\",\n    \"SESSION_STORAGE_ENABLED\": true,\n    \"SESSION_TIMEOUT_IN_MINUTES\": 360,\n    \"DESIGN_MODE_ENABLED\": true\n  },\n  \"cmsDbContext\": {\n    \"id\": \"your-id\",\n    \"connectionString\": \"mongodb://your-username:your-pwd@your-host-name:27017/admin?directConnection=true\",\n    \"databaseName\": \"elemental_playground\"\n  }\n}\n```\n\nAfter we create the config file under the name for example local.cli.json, we can issue the \"init\" command as shown below: \n\n```shell\nelemental-cms init -c settings/local.cli.json\n```\n\nExecuting this command will create and update our .elemental metadata file setting the \"configFilePath\" property to \"settings/local.cli.json\", and it will update the folder structure which will ends looking like this:\n\n```lang-none\nworkdir\n└───media    \n└───settings\n    └───local.cli.json\n└───static\n└───templates\n    └───base.html\n└───translations\n└───workspace\n    └───global_deps\n    └───pages\n    └───snippets\n└───.elemental\n```\n\n\u003e Be aware of that in Windows OS using Visual Studio 2019 after running the init command (and any other command that modify the folders and files structure), the created files and folders will not be added to the project automaticaly.\n\n## Shell Autocomplete (Optional)\n\nElemental CMS supports shell autocomplete for commands and arguments, making it faster to work with snippets, pages, and global dependencies.\n\nThe completion scripts are included in the package. To enable autocomplete, run the setup script once:\n\n```shell\n# If you cloned the repo\n./enable-completion.sh\n\n# If you installed via pip, find and run the script\nbash $(python -c \"import elementalcms, os; print(os.path.join(os.path.dirname(os.path.dirname(elementalcms.__file__)), 'enable-completion.sh'))\")\n\n# Then reload your shell\nsource ~/.zshrc  # for Zsh\n# or\nsource ~/.bashrc  # for Bash\n```\n\nOnce enabled, you can use TAB completion:\n```shell\nelemental-cms snippets diff -s \u003cTAB\u003e    # Shows available snippet names\nelemental-cms pages push -p home \u003cTAB\u003e  # Shows available languages\nelemental-cms global-deps push -d bootstrap \u003cTAB\u003e  # Shows valid types\n```\n\nFor detailed instructions and troubleshooting, see [COMPLETION.md](COMPLETION.md).\n\nTo disable autocomplete:\n```shell\n./disable-completion.sh\n```\n\n## Working with Snippets\n\nSnippets are reusable HTML components that can be included in your pages. They are managed through the `snippets` command.\n\n### Snippet Naming Rules\n- Must be lowercase (e.g., `header`, `nav-bar`)\n- Must start with a letter\n- Can only contain letters, numbers, and hyphens\n- Examples of valid names: `nav-bar`, `footer-2`, `main-menu`\n- Examples of invalid names: `Header` (uppercase), `1nav` (starts with number), `nav_bar` (underscore)\n\n### Creating a Snippet\n```shell\nelemental-cms snippets create -s nav-bar\n```\n\nThis will create two files in your SNIPPETS_FOLDER:\n- `nav-bar.json`: Contains snippet metadata and dependencies\n- `nav-bar.html`: Contains the HTML content\n\n### Managing Snippets\n```shell\n# List all snippets (shows * for snippets that: have local changes, are missing local files, or exist locally but not in the database)\nelemental-cms snippets list\n\n# Compare local and database versions of a snippet\nelemental-cms snippets diff -s nav-bar\n\n# Push a snippet to CMS\nelemental-cms snippets push -s nav-bar\n\n# Push all snippets\nelemental-cms snippets push --all\n\n# Pull a snippet from CMS\nelemental-cms snippets pull -s nav-bar\n\n# Remove a snippet\nelemental-cms snippets remove -s nav-bar\n```\n\n## Working with Pages\n\nPages are the main content units in Elemental CMS. Each page consists of a spec file (metadata) and a content file (HTML).\n\n### Creating a Page\n```shell\nelemental-cms pages create -p home en\n```\n\nThis creates two files in your PAGES_FOLDER/en directory:\n- `home.json`: Contains page metadata and dependencies\n- `home.html`: Contains the HTML content\n\n### Managing Pages\n```shell\n# List all pages (shows * for pages that: have local changes, are missing local files, or exist locally but not in the database)\nelemental-cms pages list\n\n# Compare local and database versions of a page\nelemental-cms pages diff -p home en\n\n# Compare draft version\nelemental-cms pages diff -p home en --drafts\n\n# Push a page to CMS\nelemental-cms pages push -p home en\n\n# Push all pages\nelemental-cms pages push --all\n\n# Pull a page from CMS\nelemental-cms pages pull -p home en\n\n# Pull all pages\nelemental-cms pages pull --all\n\n# Publish a page\nelemental-cms pages publish -p home en\n\n# Publish all pages that have draft versions\nelemental-cms pages publish --all\n\n# Unpublish a page\nelemental-cms pages unpublish -p home en\n\n# Remove a page\nelemental-cms pages remove -p home en\n```\n\n### Page Structure\n\n#### Spec File\nThe spec file (`home.json`) contains the page metadata:\n\n```json\n{\n    \"_id\": {\n        \"$oid\": \"619b8f70f065731d43fb11fc\"\n    },\n    \"name\": \"home\",\n    \"language\": \"en\",\n    \"title\": \"home page\",\n    \"description\": \"\",\n    \"isHome\": false,\n    \"cssDeps\": [],\n    \"jsDeps\": [],\n    \"createdAt\": {\n        \"$date\": 1637584752066\n    },\n    \"lastModifiedAt\": {\n        \"$date\": 1637584752066\n    }\n}\n```\n\n### Content file\n\nThe content file will have the HTML for the page.\n\n```html\n\u003cdiv\u003e\u003c/div\u003e\n```\n\n### Notes on Page Management\n\n1. **Draft vs Published**: When pushing a page, it creates a \"draft\" version in the database. Use `publish` to make it accessible through the web application.\n\n2. **Repository Difference Indicators**: The `list` command shows an asterisk (*) next to pages that:\n   - Have differences between local and database versions\n   - Are missing their local files\n   - Exist locally but not in the database\n\n3. **Batch Operations**: Some commands support `--all` flag:\n   - `push --all`: Push all pages\n   - `pull --all`: Pull all pages\n   - `publish --all`: Publish all pages that have draft versions\n\n## Running the app\n\nWe have created a multilanguage page and successfully published it, but we are missing our application entry point.\n\nSince this framework is based on Flask we can create an entry point just like we will do it for any other Flask application; a simple boilerplate can be found down below:\n\n```python\nimport json\nimport os\n\nfrom elementalcms import Elemental, ElementalContext\nfrom elementalcms.core import FlaskContext, MongoDbContext\nfrom flask import Flask\n\nwww = Flask(__name__, template_folder='templates', static_folder='static')\n\nCONFIG_FILEPATH = os.environ.get('CONFIG_FILEPATH', 'settings/local.www.json')\n\nwith open(CONFIG_FILEPATH) as config_file:\n    settings = json.load(config_file)\n    cms_core_context = FlaskContext(settings['cmsCoreContext'])\n    cms_db_context = MongoDbContext(settings['cmsDbContext'])\n    elemental_context = ElementalContext(cms_core_context, cms_db_context)\n\nElemental(www, elemental_context)\n\n\nif __name__ == '__main__':\n    www.run(host='0.0.0.0', port=8000)\n```\n\nNote that in order to run the app locally we need another setting file (local.www.sjon) with some minor modifications. Like the one shown below:\n\n```json\n{\n  \"cmsCoreContext\": {\n    \"DEBUG\": true,\n    \"ENV\": \"development\",\n    \"SECRET_KEY\": \"the-secret\",\n    \"SITE_NAME\": \"Elemental CMS\",\n    \"COMPANY\": \"Your company name\",\n    \"CANONICAL_URL\": \"https://elemental.cms\",\n    \"LANGUAGES\": [\n      \"en\",\n      \"es\"\n    ],\n    \"DEFAULT_LANGUAGE\": \"en\",\n    \"LANGUAGE_MODE\": \"multi\",\n    \"STATIC_FOLDER\": \"static\",\n    \"MEDIA_FOLDER\": \"media\",\n    \"STATIC_URL\": \"/static\",\n    \"MEDIA_URL\": \"/media\",\n    \"GLOBAL_DEPS_FOLDER\": \"workspace/global_deps\",\n    \"PAGES_FOLDER\": \"workspace/pages\",\n    \"SNIPPETS_FOLDER\": \"workspace/snippets\",\n    \"USER_IDENTITY_SESSION_KEY\": \"userIdentity\",\n    \"SESSION_STORAGE_ENABLED\": true,\n    \"SESSION_TIMEOUT_IN_MINUTES\": 360,\n    \"DESIGN_MODE_ENABLED\": true\n  },\n  \"cmsDbContext\": {\n    \"id\": \"your-id\",\n    \"connectionString\": \"mongodb://your-username:your-pwd@your-host-name:27017/admin?directConnection=true\",\n    \"databaseName\": \"elemental_playground\"\n  }\n}\n```\n\nIn this file we do not need buckets information, sinces static and media resoruces will be served locally. We do not need a Google Service Account niether because that info is needed only by the cli tool to send local files to GCS.\n\n## Windows OS + Visual Studio 2019\n\nIn Visual Studio 2019 we have some minor challenges to get started due to \"problems\" related with the operative system security policies more than with the tool.\n\n- We start by creating a Python project and adding a virtual environment\n- Then visual studio offers developer terminals in at least 2 flavors:\n  - **Developer PowerShell** where the environment do not get activated by default, so we must activate it by running the command:\n\n```shell\n.\\.venv\\Scripts\\Activate.ps1\n```\n\n\u003e Depending on your security policies this command will or will not ork. When it does not work it will show an error telling you something like: \"Activate.ps1 cannot be loaded because running scripts is disabled on\nthis system. For more information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.\"\n\n\u003e To overcome this situation we must enable running scripts at least to the current user, following the official Microsoft documentation.\n\n  - **Developer Command Promt** were the environment do not get activated by default, so we must activate it by running the command:\n\n```shell\n.venv\\Scripts\\activate\n```\n\n\u003e In both cases we assume you create the virtual environment under the name **.venv**\n\nResolving this minor setbacks we can go back to the \u003ca href=\"#setup\"\u003eSetup\u003c/a\u003e step and follow the getting started guide normaly.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparanoid-software%2Felemental-cms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fparanoid-software%2Felemental-cms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparanoid-software%2Felemental-cms/lists"}