SCStudioCMS
Developer Documentation

Build complete StudioCMS themes without guessing the template contract.

This guide follows the full structure of the supplied Vintage Car Rental StudioCMS theme, including front page, blog, single pages and posts, tags, gallery sections, theme settings, 404, coming-soon and maintenance templates, assets, secure forms, anti-spam and bot-abuse protection, SEO and packaging.

1. Complete theme structure

A production theme should keep its entire implementation inside one theme folder. The supplied theme uses this structure:

your-theme/ ├── 404.php ├── blog.php ├── coming_soon.php ├── footer.php ├── functions.php ├── header.php ├── index.php ├── maintenance.php ├── page.php ├── post.php ├── README.txt ├── screenshot.svg ├── send-request.php ├── style.css ├── tag.php ├── theme.json ├── theme.php ├── assets/ │ └── theme.js ├── sections/ │ ├── album.php │ ├── booking.php │ └── gallery.php └── settings/ └── options.php
Do not omit status templates just because the main website works. A complete theme needs to remain branded when StudioCMS routes the site to 404, Coming Soon, or Maintenance mode.

2. Manifest and theme bootstrap

theme.json

The marketplace and StudioCMS can identify a theme from its manifest. Keep the values plain JSON and place the file at the theme root.

{
  "name": "Your Theme Name",
  "slug": "your-theme-name",
  "version": "1.0.0",
  "author": "StudioCMS",
  "description": "A concise description of the theme.",
  "category": "Business"
}

theme.php

The supplied theme returns the display name and the settings class. Match settings_class to the class declared in settings/options.php.

<?php
return [
    'name' => 'Your Theme Name',
    'settings_class' => 'YourThemeSettings',
];

Theme screenshot

Include screenshot.webp, screenshot.jpg, screenshot.png, or screenshot.svg in the ZIP. The StudioCMS marketplace package included with this release can read the screenshot directly from the ZIP.

3. Template responsibilities

index.phpFront-page layout. Build the main sections and include shared header/footer.
blog.phpBlog archive. Iterate $posts and render $pagination when supplied.
page.phpSingle CMS page. Use $data for title, slug, description, content and page-specific routing.
post.phpSingle blog post. Use $data, including featured image/ALT and trusted rendered content.
tag.phpTag archive. The supplied theme uses $tag and $posts.
404.phpSet HTTP 404 status and render a branded not-found view.
coming_soon.phpStandalone status page used while the public site is not yet launched.
maintenance.phpStandalone maintenance status page using CMS status title/message settings.
header.php / footer.phpShared layout, navigation, SEO/head integrations, footer menus and scripts.
functions.phpTheme-only helpers, option readers, repeaters, menus, measurement helpers and native module adapters.

Supporting files that complete the theme

FileRole
style.cssPublic theme styles, responsive layouts, status-page styles, blog/page/post/gallery styling.
assets/theme.jsTheme-side interactions such as navigation, galleries, lightbox behavior or other progressive enhancements.
screenshot.svg (or supported image format)Theme preview artwork for review and marketplace display.
README.txtVersion, features, settings, installation steps, content behavior and release notes.
send-request.phpTheme request endpoint when the theme needs its own form bridge; the supplied version boots StudioCMS and uses native Forms validation/submission classes.

4. Data available to templates

TemplateObserved variables / fieldsRecommended handling
page.php$data['slug'], title, meta_description, contentEscape titles/descriptions; render CMS HTML content only where StudioCMS has already prepared it for output.
post.php$data['title'], featured_image, featured_alt, contentUse base_url() for media and escape attributes.
blog.php$posts, optional $paginationEach post may include slug, title, content, featured image and ALT text.
tag.php$tag, $postsEscape the tag title and post text.
<?php require __DIR__ . '/header.php'; ?>
<article>
  <h1><?= htmlspecialchars((string)($data['title'] ?? 'Page')) ?></h1>
  <div class="content"><?= (string)($data['content'] ?? '') ?></div>
</article>
<?php require __DIR__ . '/footer.php'; ?>

6. Theme Settings contract

settings/options.php declares a settings class. Its static fields(): array method returns field definitions. The supplied theme uses the field types image, text, textarea, number, url, and menu, grouped into Branding, Hero, Packages, Add-On Services, Gallery Image, Videos, Reservation Request, FAQ, Contact, Social, Navigation, SEO, and Google Measurement.

class YourThemeSettings
{
    public static function fields(): array
    {
        return [
            ['name'=>'logo', 'label'=>'Site Logo', 'type'=>'image', 'group'=>'Branding'],
            ['name'=>'site_name', 'label'=>'Site Name', 'type'=>'text', 'group'=>'Branding'],
            ['name'=>'seo_title', 'label'=>'SEO Title', 'type'=>'text', 'group'=>'SEO'],
            ['name'=>'meta_description', 'label'=>'Default Meta Description', 'type'=>'textarea', 'group'=>'SEO'],
            ['name'=>'seo_keywords', 'label'=>'SEO Keywords', 'type'=>'text', 'group'=>'SEO'],
        ];
    }
}

Use ThemeOptions::get() to read stored values. If you seed defaults, only create a default when the option does not already exist; never overwrite an administrator's saved customization during a theme update.

7. Sections, Gallery and native CMS modules

Reusable front-page blocks can live under sections/. The supplied theme has separate booking, gallery and album templates. The gallery uses native StudioCMS gallery records and creates album URLs such as /gallery/{album-slug}. Album pages use server-side pagination and read native gallery album/image data through the CMS database object.

Keep reusable UI in section files, but keep routing decisions in the primary template. In the supplied theme, page.php detects the Gallery page and loads either sections/gallery.php or sections/album.php when an album is requested.

8. 404, Coming Soon and Maintenance

404

<?php
http_response_code(404);
require __DIR__.'/header.php';
?>
<section class="not-found">...</section>
<?php require __DIR__.'/footer.php'; ?>

Coming Soon

The supplied status template uses Settings::get('coming_title') and Settings::get('coming_message'), sets noindex,nofollow, reads the theme logo/favicon, and can show theme contact details.

Maintenance

Use the same standalone pattern with maintenance_title and maintenance_message. Status pages should not rely on front-page sections being available, and they should work even when normal public routing is disabled.

9. Forms, anti-spam and bot-abuse protection

The supplied theme integrates with StudioCMS Forms instead of creating theme-specific tables. Its booking/contact section should load the native Forms renderer, while send-request.php boots StudioCMS and uses the core Forms validator, anti-spam, rate-limit, upload and submission classes.

Do not build a second JavaScript submit pipeline around the native StudioCMS Forms renderer. A duplicate AJAX handler can cause the same form to be submitted twice and may trigger the anti-abuse rate limiter even for a real visitor.

Required public-form protections

Every public theme form should use the StudioCMS protections below. The theme should not attempt to reimplement these checks with custom database tables or client-side JavaScript alone.

ProtectionPurposeTheme responsibility
CSRF validationRejects forged cross-site submissions.Render the native form token and validate it in send-request.php before processing input.
Honeypot / bot trapStops simple automated form-fill bots.Render the StudioCMS honeypot field and reject submissions when it is populated.
Signed render timeProves the form was rendered by StudioCMS and lets the server measure submission timing.Preserve the native signed timing fields generated by the Forms renderer.
Minimum submit delayRejects unrealistically fast submissions commonly produced by bots.Use the core anti-spam validator; do not hard-code timing logic inside the theme.
Stale-form protectionRejects very old or replayed form submissions.Allow StudioCMS to validate the signed form age server-side.
Per-IP rate limitingLimits repeated attempts and automated abuse.Use the native rate limiter and display the returned warning to the visitor.
Link / payload checksBlocks excessive links and obvious spam payloads.Pass the submitted values through the StudioCMS anti-spam service before saving or emailing.
Secure uploadsPrevents unsafe filenames and unsupported file types.Use StudioCMS Upload::validate() and Upload::filename(); never trust the browser filename or MIME type by itself.

Recommended send-request.php flow

<?php
// 1. Boot StudioCMS.
require_once __DIR__ . '/../../bootstrap.php';

// 2. Accept POST only.
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit;
}

// 3. Validate the native StudioCMS form security fields.
//    This includes CSRF, honeypot, signed timing, minimum-submit
//    delay, stale-form checks and rate limiting.
$spamResult = FormAntiSpam::validate($_POST, $_SERVER);

if (!$spamResult['ok']) {
    // Return a visible validation / anti-abuse message.
    // Example: "Too many request attempts. Please try again later."
    // Do not silently hide this from the user.
    // ...
}

// 4. Validate normal form fields with the native Forms validator.
// 5. Validate uploads with Upload::validate().
// 6. Generate stored filenames with Upload::filename().
// 7. Submit through the native Forms submission service.

Visible validation and anti-abuse messages

A secure form is not complete if the visitor cannot read the response. Theme CSS must keep validation errors, anti-spam warnings, rate-limit messages and success messages visible against the form background. Avoid setting these containers to transparent text, low opacity or colors that match the panel behind them.

/* Example theme-side visibility rules */
.cms-form-alert-error,
.cms-form-alert-error *,
.cms-form-errors,
.cms-form-errors *,
[role="alert"],
[role="alert"] * {
    color: #111 !important;
    opacity: 1 !important;
    visibility: visible !important;
}

.cms-form-alert-success,
.cms-form-alert-success * {
    color: #111 !important;
    opacity: 1 !important;
    visibility: visible !important;
}

Mobile date fields

Native iOS/Safari date inputs can keep an intrinsic width that overflows a responsive form card. Themes that use input[type="date"] should explicitly constrain the field and its grid wrapper.

.cms-form-field {
    min-width: 0;
    max-width: 100%;
}

input[type="date"] {
    -webkit-appearance: none;
    appearance: none;
    display: block;
    box-sizing: border-box;
    width: 100%;
    min-width: 0;
    max-width: 100%;
}

@media (max-width: 760px) {
    .cms-form-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}
Prefer native StudioCMS Forms and Gallery services. Avoid creating custom theme database tables unless the CMS explicitly requires them. Anti-spam, bot-abuse controls and secure upload validation must run server-side even when the theme also provides client-side validation.

10. Google measurement and developer integrations

The supplied settings expose GA4 Measurement ID, Google Tag Manager Container ID, Google Ads Conversion ID/label, and Search Console verification token. Measurement output is handled through theme helper functions. Header integration also checks for ThemeDeveloperContract before rendering CMS-provided head integrations.

Validate identifiers before output, escape verification values, and do not hard-code a client's tracking credentials into a redistributable theme ZIP.

11. Security and portability rules

  • Escape text and attributes with htmlspecialchars(..., ENT_QUOTES, 'UTF-8').
  • Use base_url() rather than absolute domain URLs.
  • Use basename() when a stored media filename is expected, to prevent path traversal.
  • Do not put API secrets, SMTP passwords, PayPal secrets, or private credentials inside a theme.
  • Do not trust query-string values. Validate album slugs, IDs, pagination numbers and form input.
  • All public forms must use StudioCMS CSRF validation, honeypot checks, signed render timing, minimum-submit delay, stale-form protection and per-IP rate limiting.
  • Pass public form text through the native anti-spam checks for excessive links and obvious bot/spam payloads before saving or emailing.
  • Validate uploads with the StudioCMS upload service and generate safe stored filenames; never trust a user-supplied filename, extension or MIME type alone.
  • Display validation, anti-spam, rate-limit and success messages clearly; security feedback must not be hidden by theme colors or CSS.
  • Avoid duplicate JavaScript submit handlers when using the StudioCMS native Forms renderer, because double submissions can trigger abuse protection and create duplicate entries.
  • Use the CMS database layer with bound parameters for native data queries.
  • Keep status templates independent and set correct HTTP/robots behavior.
  • Lazy-load non-critical images and provide meaningful ALT text.

12. ZIP packaging checklist

  1. The ZIP contains one root theme folder—not loose files mixed at archive root.
  2. theme.json has name, slug, version, author, description and category.
  3. theme.php points to the correct settings class.
  4. Include index.php, page.php, post.php, blog.php, tag.php, 404.php, coming_soon.php, and maintenance.php.
  5. Include header.php, footer.php, functions.php, CSS and JS assets.
  6. Include settings/options.php and any reusable sections/.
  7. If the theme has a public form, verify CSRF, honeypot, signed timing, minimum-submit delay, stale-form protection, per-IP rate limiting, spam/link checks and secure upload handling.
  8. Verify all form validation, anti-spam, rate-limit and success messages remain readable on desktop and mobile.
  9. Verify input[type="date"] does not overflow its form card on iOS/Safari.
  10. Include a screenshot and README with version, features and install notes.
  11. Test the home page, page, post, blog pagination, tag archive, 404, Coming Soon, Maintenance, forms, Gallery, mobile navigation, SEO output and all Theme Settings before release.

Browse StudioCMS Themes