Fix LCP Issues on Cmsmadesimple (Loading Speed) | OpsBlu Docs

Fix LCP Issues on Cmsmadesimple (Loading Speed)

Reduce CMS Made Simple LCP by enabling Smarty template caching, compressing uploaded images, and consolidating module stylesheets.

General Guide: See Global LCP Guide for universal concepts and fixes.

What is LCP?

Largest Contentful Paint measures when the largest content element becomes visible. Google recommends LCP under 2.5 seconds. CMS Made Simple (CMSMS) uses the Smarty template engine with a MySQL backend, so LCP depends on Smarty template caching, module query performance, and theme asset loading.

CMSMS-Specific LCP Causes

  • Smarty template compilation on every request -- without caching, CMSMS compiles Smarty templates from scratch, adding 200-800ms to TTFB
  • Module overhead -- each active module (News, Gallery, FormBuilder) runs PHP and database queries on page load even if not used on that page
  • No built-in image processing -- uploaded images serve at original resolution from uploads/images/
  • Render-blocking module CSS/JS -- modules inject their own stylesheets and scripts into {cms_head_css} and {cms_head_js} tags synchronously
  • Shared hosting limitations -- CMSMS is commonly deployed on cheap shared hosting with slow PHP execution

Fixes

1. Enable Smarty Template Caching

Configure CMSMS to cache compiled Smarty templates. In config.php:

// config.php -- enable Smarty caching
$config['smarty_caching'] = true;
$config['smarty_cache_lifetime'] = 3600; // 1 hour

// Also enable content caching in Admin > Global Settings > Performance
// Set "Cache content" to Yes
// Set "Cache template compilations" to Yes

Additionally, enable CMSMS's built-in page caching at Admin > Extensions > Page Caching:

// Or via config.php
$config['page_cache'] = true;
$config['page_cache_expiry'] = 3600;

2. Optimize Images Before Upload

CMSMS has no image processing pipeline. Use server-side optimization or pre-process before uploading:

# Server-side: optimize all uploaded images
find uploads/images/ -name "*.jpg" -exec mogrify -strip -quality 80 -resize "1920>" {} \;
find uploads/images/ -name "*.png" -exec optipng -o2 {} \;

In your Smarty template, add responsive image attributes:

{* In your page template *}
{if $content_obj->GetPropertyValue('hero_image')}
  <img
    src="{uploads_url}/images/{$content_obj->GetPropertyValue('hero_image')}"
    width="1200" height="630"
    alt="{$content_obj->Name()|cms_escape}"
    loading="eager"
    fetchpriority="high"
    style="aspect-ratio: 1200/630; width: 100%; height: auto; object-fit: cover;"
  >
{/if}

3. Reduce Module Load Overhead

Disable unused modules at Admin > Extensions > Modules. Common heavy modules to audit:

  • News -- runs database queries even on non-news pages if loaded globally
  • Gallery/Album -- loads jQuery plugins on every page
  • FormBuilder -- injects validation scripts site-wide

For modules you keep, use conditional loading in templates:

{* Only load Gallery assets on gallery pages *}
{if $page_alias == 'gallery'}
  {Gallery action='default' ...}
{/if}

4. Consolidate and Defer Theme Assets

CMSMS modules inject CSS/JS via {cms_head_css} and {cms_head_js}. Optimize your layout template:

{* In your layout template *}
<head>
  {* Inline critical CSS *}
  <style>
    .header { display: flex; height: 64px; }
    .hero { width: 100%; aspect-ratio: 16/9; }
    body { font-family: system-ui, sans-serif; margin: 0; }
  </style>

  {* Preload hero image on homepage *}
  {if $page_alias == 'home'}
    <link rel="preload" as="image" href="{uploads_url}/images/hero.jpg">
  {/if}

  {* Load module CSS but defer non-critical *}
  {cms_head_css}
</head>
<body>
  {content}

  {* Move JS to bottom and add defer *}
  {cms_head_js}
  <script defer src="{root_url}/themes/{$gCms->GetConfig()->smarty_cachedir}/../yourtheme/js/theme.js"></script>
</body>

5. Add Server-Level Caching

Configure .htaccess for asset caching:

# .htaccess in CMSMS root
<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType image/webp "access plus 1 year"
  ExpiresByType text/css "access plus 1 month"
  ExpiresByType application/javascript "access plus 1 month"
</IfModule>

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json
</IfModule>

Measuring LCP on CMSMS

  • CMSMS Admin > Extensions > Page Caching -- check cache hit rates to see how often pages are served from cache
  • PageSpeed Insights -- test homepage, content pages, and any pages using heavy modules (Gallery, News)
  • TTFB check -- curl -w "TTFB: %{time_starttransfer}\n" -o /dev/null -s https://yoursite.com -- if over 800ms, focus on caching before frontend optimization
  • PHP profiling -- if you have access, use Xdebug or Blackfire to profile which modules consume the most execution time

Analytics Script Impact

CMSMS analytics are typically added via the CGSmartImage or custom User Defined Tags (UDTs):

  • Ensure any analytics UDT outputs async or defer attributes on script tags
  • If using the Google Analytics module from the Forge, verify it outputs async gtag.js
  • Place tracking code in the layout template after {content} rather than in <head>