Geoff MooreandClaude Sonnet 5 d3f196570d Add site scan, editor-based publishing workflow and subfolder support
Adds a whole-site "Site scan" that analyses pages, images and SEO tags and
makes pages editable in one step, moves Save Draft / Schedule Publish /
Publish Now into the content editor, supports installs in a subfolder, and
hardens metadata handling. Only the cms/ directory is changed.

Added
- Site scan (Tools > Site scan, administrators): reports pages, folders,
  editable/untagged pages, images without alt text, broken local
  references, unused uploads and missing title/description/Open Graph
  tags; then tags <main> or top-level article/section content areas,
  images outside editable regions and photo placeholders, and inserts only
  missing SEO tags. Page source is edited byte-for-byte (no DOM
  re-serialisation), a revision is kept for every changed page, later scans
  list only pages that still need changes, and work runs in small batches
  with a progress bar and "N of M pages" count. New administrator-only
  actions: listSitePages, analyseSitePages, applySiteTagging.
- Click-to-edit images and photo placeholders (role="img" boxes) with a
  Media Library picker and alt text.
- Subfolder installs (basePath / siteRoot auto-detected); root installs
  behave as before.
- Audit/activity entries for cancelled schedules, image uploads, alt-text
  changes and failed scheduled publications (shared Activity class).
- Snackbar (success/error) and table-style dialogs for the page picker,
  revision history, dashboard, shared content, menus and site scan.

Changed
- Editor actions are now Save Draft | Schedule Publish | Publish Now |
  Cancel; saving in the editor and applying image/SEO changes stores a
  private draft. The toolbar no longer has Save Draft, Schedule or Publish.
- CMSController split into PagePaths, ContentDom and Activity; entry points
  share cms/bootstrap.php. Restoring a deleted page uses
  PageNotFoundException instead of matching an error message.

Fixed
- Lost updates on JSON metadata (locked FileStore::update).
- Non-atomic site-wide shared-content/menu writes; non-ASCII text handling.
- Scheduled publishing contending for a lock on every request.
- Revision pruning dropping the newest revision (revisions gain a "ts").
- Stale cached pages in the editor preview after a site is replaced.
- Saved drafts reloading without stylesheets or the correct page path, and
  Publish discarding a draft that was not re-offered in the same session.
- HTML entities in page titles; backslashes in folder names on Windows.

Migration: no manual steps. basePath/siteRoot are optional and detected
automatically. The analyseSite action was replaced by listSitePages and
analyseSitePages.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 13:17:09 +01:00
2024-10-03 08:07:53 +01:00
2026-06-08 17:12:42 +01:00
2026-06-08 17:12:42 +01:00
2026-06-08 17:12:42 +01:00
2026-06-08 17:12:42 +01:00
2026-06-08 17:12:42 +01:00
2024-10-03 08:27:27 +01:00
2026-06-08 17:12:42 +01:00

NeoCMS

Version 3.0

Welcome to NeoCMS, the lightweight, database-free content management system. Built with PHP and JavaScript, NeoCMS is designed to add controlled visual editing to an existing static website without changing how public pages are served.

Version 3.0 adds filesystem-backed drafts, revision history, role-based permissions, scheduled publishing, page and media management, SEO controls, shared content, navigation menus, responsive previews, accessibility checks, and an operational dashboard. Public content remains ordinary HTML; the database server may continue its well-earned rest.

Further technical documentation:

Features

  • No Database Required: NeoCMS works without a database, so you don’t have to worry about setup hassles or performance slowdowns.
  • Easy Content Editing: The TinyMCE visual editor updates marked content regions without requiring authors to edit HTML. Adding neo-dupe allows an element and its children to be cloned or removed.
  • Seamless Integration: Simply add the CMS to any existing static website. Just assign a special class to the elements you want to make editable, and you’re all set.
  • Consistent Layouts: NeoCMS supports page templates to keep your layouts neat and uniform across all pages.
  • Drafts and Publishing: Editors can save drafts without changing the public page. Publishers can publish immediately or schedule a publication.
  • Revision History: Every changed or deleted page receives a timestamped filesystem snapshot that publishers can restore.
  • Page Management: Search, create, duplicate, rename, and delete editable HTML pages, including pages in subdirectories.
  • Media Library: Browse uploaded images, reuse them, maintain alternative text, see usage counts, and remove files.
  • SEO Settings: Edit the page title, description, canonical URL, Open Graph image, and robots indexing setting.
  • Shared Content: Mark content with data-neo-shared="name" and update matching regions across the site.
  • Navigation Menus: Build ordered and nested navigation markup and insert it into an editable region.
  • Responsive Preview: Preview the current page at desktop, tablet, and mobile widths.
  • Accessibility Checks: Check common authoring problems such as missing alt text, empty links, heading jumps, missing labels, and absent page metadata before publishing.
  • Roles and Activity: Use editor, publisher, and administrator roles. The dashboard displays drafts, schedules, system problems, and recent activity.

Installation Guide

To install NeoCMS:

  • Place the cms/ directory in the document root of the static website.
  • Place the uploads/ directory in the same document root.
  • Copy cms/config.local.php.example to cms/config.local.php, add password hashes, and assign roles.
  • Update the elements you want to make editable by adding the configured editable class. It is editable by default.
  • Confirm that PHP may write to the managed HTML files, cms/data/, cms/logs/, and uploads/.
  • Visit /cms/, log in, and begin editing.

That’s it! You’re up and running.

Configuration

Tracked defaults live in cms/config.php. Deployment credentials and overrides belong in the Git-ignored cms/config.local.php, which must return an array. The supplied Apache rules deny direct access to both files.

Setting Type Purpose
authentication array Maps usernames to password_hash() values; plaintext credentials are rejected.
roles array Maps usernames to editor, publisher, or administrator.
security array Configures session expiry, login throttling, request limits, storage quotas, and audit-log retention.
uploads array Configures image size, dimension, file-count, and aggregate-storage limits.
audit boolean Enables daily activity logs under cms/logs/.
skipWelcomePage boolean Opens the public root instead of the built-in guide after login.
showFullUrl boolean Displays the current page path in the toolbar.
editableClass string Selects the single CSS class used to identify editable regions.

dataDirectory is an internal override used by the integration suite and specialised deployments. Normal installations should allow NeoCMS to use cms/data/.

Editable Class

The class used to identify editable regions is configurable:

'editableClass' => 'editable',

Set it to any single valid CSS class name without a leading dot, for example:

'editableClass' => 'cms-content',

Your page markup must then use that class:

<section class="cms-content">This region can be edited.</section>

Invalid configured values fall back to editable. The neo-dupe class remains fixed because it marks repeatable blocks, not general editable content. When overriding editableClass, update the classes in cms/templates/ as well so newly created pages are immediately discoverable by the page picker.

Users and Roles

Passwords must be generated with password_hash() and stored under authentication in cms/config.local.php. Assign the same username a role under roles:

'authentication' => [
    'author' => '$2y$10$...',
    'publisher' => '$2y$10$...',
],
'roles' => [
    'author' => 'editor',
    'publisher' => 'publisher',
],
  • editor: edit content, save drafts, and upload media.
  • publisher: editor permissions plus immediate and scheduled publishing and revision restoration.
  • administrator: publisher permissions plus page, media, shared-content, and menu management.

Users without an explicit valid role receive editor, the least powerful role. Account removal, password-hash changes, and role changes affect active sessions on their next request. Sessions expire after 30 minutes of inactivity and 12 hours in total by default.

When HTTPS terminates at a trusted reverse proxy, set 'cookieSecure' => true beneath security in the local override. This keeps the session cookie marked Secure even when PHP receives the proxy's internal HTTP request.

Audit files rotate at 10 MiB and are retained for 90 days by default. Override auditMaxFileBytes and auditRetentionDays beneath security where local retention obligations differ.

Password Hash Example

Generate a hash on a trusted command line, then place only the resulting hash in cms/config.local.php:

php -r 'echo password_hash(trim(fgets(STDIN)), PASSWORD_DEFAULT), PHP_EOL;'

There is deliberately no enabled default account.

Content Features

Repeatable Blocks

Add neo-dupe alongside the configured editable class. The editor provides clone-before, clone-after, and delete controls:

<article class="editable neo-dupe">Repeatable content</article>

Shared Content

Use data-neo-shared to identify a global region:

<footer class="editable" data-neo-shared="site-footer">Shared footer content</footer>

The Shared Content tool updates every HTML page containing the same key. Publishing a page also captures the current value of its shared regions.

Navigation Menus

Menu items use one line each in this format:

Home | /
About | /about.html
Team | /team.html | About

The optional third value is the label of the parent item. After saving, the generated <nav> can be inserted into the currently selected editable region.

Drafts and Revisions

Drafts do not alter public HTML. When opening a page with a saved draft, NeoCMS offers to load it. Publishing creates a revision of the previous public file first. Deleting a page also retains its last revision.

NeoCMS stores metadata, drafts, scheduled content, and revisions under cms/data/. Back up this directory together with the website. The supplied .htaccess denies direct HTTP access on Apache; other web servers should deny /cms/data/ and /cms/logs/ explicitly. Private directories and files are created with owner-only permissions where the operating system permits it. Configurable quotas bound drafts, schedules, revisions, and uploaded media to reduce disk-exhaustion risk.

Scheduled Publishing

Due schedules are processed whenever the CMS API is used. For publication without an active CMS user, run the CLI worker once per minute with cron:

* * * * * /usr/bin/php /absolute/path/to/site/cms/publish_scheduled.php >/dev/null 2>&1

The server timezone controls PHP date handling; the browser converts the selected local time to an absolute timestamp.

Administration Workflow

  1. Open a page from Pages.
  2. Select a region carrying the configured editable class and edit it in TinyMCE.
  3. Use Save Draft to retain private work, or Publish to replace the public HTML after creating a revision.
  4. Use Schedule when publication should occur later.
  5. Check revisions, accessibility findings, SEO metadata, shared content, and menus through the relevant toolbar dialogues.

The Save button inside the content-editor modal only applies content to the in-browser preview. It does not write a public file. This distinction is intentional and prevents an innocent wording change from making an unscheduled public debut.

Page Markup Recommendations

For the best SEO and accessibility results, each page should include one <h1>, a non-empty <title>, a meta description, alternative text on every image, descriptive link text, and labels associated with form fields. The checker highlights common authoring issues but is not a complete accessibility audit.

Requirements

  • PHP 8 running on Linux
  • PHP DOM and fileinfo extensions
  • PHP sessions enabled
  • Write access to cms/data/, cms/logs/, uploads/, and managed HTML pages
  • A modern browser with JavaScript enabled

The administration shell loads jQuery 4.0.0 and jQuery UI 1.14.2 from the official jQuery CDN with Subresource Integrity. TinyMCE 8.6.0 is bundled locally. Installations that must operate without internet access should self-host the two jQuery assets and update both cms/index.php and the administration Content Security Policy.

Web Server Security

Apache users should allow the supplied .htaccess rules. For Nginx, add equivalent rules such as:

location ^~ /cms/data/ { deny all; }
location ^~ /cms/logs/ { deny all; }
location ~ ^/cms/(config(?:\.local)?\.php|config\.local\.php\.example|publish_scheduled\.php)$ { deny all; }
location ~ ^/uploads/.*\.(php[0-9]?|phtml|phar|cgi|pl|py|sh)$ { deny all; }

Also disable directory listings, prevent PHP source download through server misconfiguration, serve the CMS only over HTTPS, and back up both public HTML and cms/data/. NeoCMS sends CSP, anti-framing, no-sniffing, referrer, permissions, cross-origin isolation, no-store, and HTTPS HSTS headers where appropriate.

Set request-body limits in the web server and PHP as well as in NeoCMS. For the default upload and API limits, a 12 MiB server limit leaves room for form overhead without letting oversized requests make themselves at home. For example:

client_max_body_size 12m;
client_body_timeout 15s;

Match post_max_size and upload_max_filesize to your configured security.maxRequestBytes and uploads.maxFileBytes.

The page preview iframe is sandboxed with allow-same-origin but without allow-scripts. This preserves DOM editing while preventing public page scripts from reaching the parent administration session.

Testing

Run the dependency-free integration suite with:

php tests/run.php

It exercises authentication hardening, session revocation, login throttling, iframe sandboxing, path containment, content limits, configurable editable regions, drafts, publication, revisions, page operations, shared content, menus, and scheduled publishing in temporary directories. See Development and testing for the complete check list used by this repository.

Licence

NeoCMS is open-source software licensed under the GNU General Public Licence v3.0 (GPLv3). You are free to use, modify, and distribute this software under the terms of this licence.

For the complete terms, see LICENSE.

Found a Bug?

Report defects and feature requests through the project's GitHub issue tracker.

Release 2.0
Latest
2024-12-02 20:40:22 +01:00
Languages
JavaScript 74.4%
CSS 17.7%
PHP 3.9%
TypeScript 3.9%
HTML 0.1%