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. Fork CMS is built on Symfony with Twig templates and a MySQL backend. LCP depends on Symfony's cache layer, Twig template rendering, and module asset loading.
Fork CMS-Specific LCP Causes
- No HTTP cache by default -- Fork CMS ships without HTTP caching enabled, so every request processes through the full Symfony pipeline
- Module asset loading -- each active module (Blog, FAQ, Mailmotor) injects its own CSS/JS files in the
<head> - Unoptimized uploads -- images uploaded via the media library serve at original resolution
- Twig template nesting -- deeply nested
{% include %}and{% block %}calls slow template compilation - Locale/translation overhead -- multi-language sites run additional database queries per request for translations
Fixes
1. Enable HTTP Caching
Configure Symfony's HTTP cache in Fork CMS:
# app/config/config_prod.yml
framework:
http_cache:
enabled: true
default_ttl: 3600
Or use Varnish in front of Fork CMS:
# /etc/varnish/default.vcl
sub vcl_backend_response {
if (beresp.http.Cache-Control !~ "private") {
set beresp.ttl = 1h;
}
}
2. Optimize Image Output in Templates
Override Fork's image templates to include dimensions and responsive attributes:
{# In your theme's Twig templates #}
{% if page.image %}
<img
src="{{ FRONTEND_FILES_URL }}/{{ page.image }}"
width="1200" height="630"
alt="{{ page.title }}"
loading="eager"
fetchpriority="high"
style="aspect-ratio: 1200/630; width: 100%; height: auto; object-fit: cover;"
>
{% endif %}
Pre-optimize images before upload:
# Optimize uploaded images
find src/Frontend/Files/ -name "*.jpg" -exec mogrify -strip -quality 80 -resize "1920>" {} \;
3. Consolidate Module Assets
Reduce the number of CSS/JS files by combining them in your theme:
{# In your base 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 #}
{% if page.image %}
<link rel="preload" as="image" href="{{ FRONTEND_FILES_URL }}/{{ page.image }}">
{% endif %}
</head>
<body>
{% block content %}{% endblock %}
{# Move all JS to bottom #}
{{ block('javascript') }}
<script defer src="{{ THEME_URL }}/js/theme.bundle.js"></script>
</body>
4. Optimize Database Queries
Fork CMS modules can be query-heavy. Optimize blog and content listing pages:
// In your module's model, use query caching
public function getRecentPosts(int $limit = 10): array
{
$cacheKey = 'blog_recent_' . $limit;
$cached = $this->cache->get($cacheKey);
if ($cached !== null) return $cached;
$posts = $this->repository->findBy(
['status' => 'active', 'language' => LANGUAGE],
['publish_on' => 'DESC'],
$limit
);
$this->cache->set($cacheKey, $posts, 1800);
return $posts;
}
5. Add Server-Level Caching
# .htaccess
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpeg "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>
Measuring LCP on Fork CMS
- Symfony Profiler (dev mode) -- shows query count, template render time, and cache status
- PageSpeed Insights -- test homepage, blog listing, and individual post pages
- TTFB check --
curl -w "TTFB: %{time_starttransfer}\n" -o /dev/null -s https://yoursite.com - Module audit -- disable modules one at a time to measure their individual LCP impact
Analytics Script Impact
Fork CMS has a built-in Google Analytics integration module. Ensure it outputs async scripts:
- Check Settings > Modules > Analytics configuration
- If adding custom tracking, place it in the theme's footer partial with
async/defer