Largest Contentful Paint (LCP) measures how quickly the main content of your Concrete CMS site loads. Poor LCP directly impacts SEO rankings and conversion rates.
Target: LCP under 2.5 seconds Good: Under 2.5s | Needs Improvement: 2.5-4.0s | Poor: Over 4.0s
For general LCP concepts, see the global LCP guide.
Concrete CMS-Specific LCP Issues
1. Unoptimized Block Images
The most common LCP issue on Concrete CMS sites is large, unoptimized images in blocks.
Problem: Image blocks loading full-resolution images instead of thumbnails.
Diagnosis:
- Run PageSpeed Insights
- Check if hero image is flagged as LCP element
- Look for "Properly size images" warning
- Check if image thumbnails are being generated
Solutions:
A. Use Concrete CMS Thumbnail System
Concrete CMS automatically generates thumbnails for uploaded images. Ensure your theme uses them:
<?php
// In your block template or theme
$image = $this->controller->get('image'); // File object
if ($image) {
// Use thumbnail instead of full image
$thumbnail = $image->getThumbnail('large'); // or custom thumbnail type
?>
<img
src="<?php echo $thumbnail->src; ?>"
width="<?php echo $thumbnail->width; ?>"
height="<?php echo $thumbnail->height; ?>"
alt="<?php echo $image->getTitle(); ?>"
loading="eager"
>
<?php
}
?>
B. Define Custom Thumbnail Types
Create custom thumbnail sizes for your needs:
Edit /application/config/concrete.php or create /application/config/generated_overrides/concrete.php:
return [
'thumbnails' => [
'types' => [
'hero_image' => [
'width' => 1920,
'height' => 800,
'crop' => false,
'quality' => 80
],
'content_image' => [
'width' => 1200,
'height' => 675,
'crop' => false,
'quality' => 85
]
]
]
];
Then use in templates:
$thumbnail = $image->getThumbnail('hero_image');
C. Implement Responsive Images
Use srcset for responsive images:
<?php
if ($image) {
$thumb_sm = $image->getThumbnail('small');
$thumb_md = $image->getThumbnail('medium');
$thumb_lg = $image->getThumbnail('large');
?>
<img
src="<?php echo $thumb_lg->src; ?>"
srcset="<?php echo $thumb_sm->src; ?> 375w,
<?php echo $thumb_md->src; ?> 768w,
<?php echo $thumb_lg->src; ?> 1200w"
sizes="100vw"
width="<?php echo $thumb_lg->width; ?>"
height="<?php echo $thumb_lg->height; ?>"
alt="<?php echo $image->getTitle(); ?>"
loading="eager"
>
<?php
}
?>
D. Enable Native Lazy Loading
For below-fold images:
<img
src="<?php echo $thumbnail->src; ?>"
loading="lazy"
width="<?php echo $thumbnail->width; ?>"
height="<?php echo $thumbnail->height; ?>"
alt="<?php echo $image->getTitle(); ?>"
>
Important: Do NOT use loading="lazy" on hero/above-fold images.
2. Theme Asset Optimization
Heavy CSS and JavaScript in themes can delay LCP.
Identify Render-Blocking Resources
Run PageSpeed Insights and look for:
- "Eliminate render-blocking resources"
- "Reduce unused JavaScript"
- "Reduce unused CSS"
Solutions:
A. Use Concrete CMS Asset System
Properly register and require assets:
In page_theme.php:
<?php
namespace Application\Theme\YourTheme;
use Concrete\Core\Page\Theme\Theme;
class PageTheme extends Theme
{
public function registerAssets()
{
// Register JavaScript with defer
$this->requireAsset('javascript', 'jquery');
$this->providesAsset('javascript', 'theme-js');
// Register CSS
$this->providesAsset('css', 'theme-css');
}
public function getThemeBlockClasses()
{
return [];
}
}
Register assets in elements.php:
return [
'javascript' => [
'theme-js' => [
'file' => 'js/main.js',
'minify' => true,
'combine' => true,
'defer' => true // Add defer attribute
]
],
'css' => [
'theme-css' => [
'file' => 'css/main.css',
'minify' => true,
'combine' => true
]
]
];
B. Inline Critical CSS
For above-fold styles, inline them in <head>:
<!-- In your page template -->
<style>
/* Critical CSS for hero section */
.hero-section {
width: 100%;
min-height: 600px;
/* ... */
}
</style>
<?php
// Load full CSS asynchronously
$this->requireAsset('css', 'theme-css');
?>
C. Defer Non-Critical JavaScript
Ensure scripts use defer or async:
<?php
// In template
$this->addHeaderItem('<script src="' . $this->getThemePath() . '/js/non-critical.js" defer></script>');
?>
D. Minify and Combine Assets
Enable in Concrete CMS settings:
Dashboard → System & Settings → Optimization → Cache & Speed Settings
- ✓ Enable CSS Cache
- ✓ Enable JavaScript Cache
- ✓ Minify CSS
- ✓ Minify JavaScript
- ✓ Combine CSS files
- ✓ Combine JavaScript files
3. Block Performance
Heavy blocks can significantly impact LCP.
Problematic Blocks:
- Image sliders/carousels
- Video backgrounds
- Complex grid layouts
- AJAX-loaded content
- Social media feeds
- Heavy form blocks
Solutions:
A. Optimize Carousel/Slider Blocks
<?php
// In custom slider block template
// Preload first slide image
if (isset($slides[0])) {
$firstImage = $slides[0]->getImageFile();
$thumbnail = $firstImage->getThumbnail('large');
?>
<link rel="preload" as="image" href="<?php echo $thumbnail->src; ?>">
<?php
}
// Lazy load subsequent slides
foreach ($slides as $index => $slide) {
$image = $slide->getImageFile();
$thumbnail = $image->getThumbnail('large');
?>
<img
src="<?php echo $thumbnail->src; ?>"
loading="<?php echo $index === 0 ? 'eager' : 'lazy'; ?>"
width="<?php echo $thumbnail->width; ?>"
height="<?php echo $thumbnail->height; ?>"
alt="<?php echo $slide->getTitle(); ?>"
>
<?php
}
?>
B. Defer AJAX Content
// Don't load AJAX content until after LCP
window.addEventListener('load', function() {
// Load AJAX content here
loadDynamicContent();
});
C. Remove Unused Blocks
- Audit pages for unused blocks
- Remove blocks that don't add value
- Consolidate functionality where possible
4. Marketplace Add-on Overhead
Add-ons are a common source of performance issues.
Audit Add-on Impact
Disable Add-ons One at a Time:
- Dashboard → System & Settings → Environment → Debug Settings
- Enable debug mode
- Test performance with/without specific add-ons
Measure Script Load Time:
- Use Chrome DevTools Network tab
- Look for scripts from add-on vendors
- Check script sizes and load times
Common Problematic Add-ons:
- Page builder add-ons (can be heavy)
- Social media integration add-ons
- Complex form builders
- Live chat widgets
Solutions:
A. Remove Unused Add-ons
Dashboard → Extend Concrete CMS → Uninstall
Important: Uninstalling removes add-on code. Don't just disable.
B. Optimize Add-on Loading
For add-ons you must keep, defer their scripts:
<?php
// In page template
if (!$c->isEditMode()) {
?>
<script>
// Delay add-on scripts until after LCP
window.addEventListener('load', function() {
// Load add-on scripts here
const script = document.createElement('script');
script.src = '/path/to/addon/script.js';
document.body.appendChild(script);
});
</script>
<?php
}
?>
C. Use Lightweight Alternatives
- Replace heavy add-ons with lighter alternatives
- Build custom blocks for specific needs
- Use native Concrete CMS features when possible
5. Caching Configuration
Proper caching is critical for LCP.
Enable Full Page Caching
Dashboard → System & Settings → Optimization → Cache & Speed Settings
Full Page Caching:
- ✓ Enable Full Page Caching
- Set cache lifetime (recommended: 3600 seconds for public pages)
- Exclude edit mode and dashboard
Block Caching:
- Enable for static blocks
- Be careful with dynamic content blocks
Asset Caching:
- ✓ Enable CSS Cache
- ✓ Enable JavaScript Cache
Configure Opcache
Edit /etc/php/8.x/fpm/php.ini:
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0
opcache.save_comments=1
Restart PHP-FPM after changes.
Use Redis for Object Caching
Install Redis:
apt-get install redis-server php-redis
Configure Concrete CMS:
Edit /application/config/database.php:
return [
'default-connection' => 'concrete',
'connections' => [
'concrete' => [
'driver' => 'concrete_pdo_mysql',
// ... database config
]
],
'redis' => [
'host' => '127.0.0.1',
'port' => 6379,
'password' => null,
'database' => 0
]
];
Then enable in Concrete CMS settings.
6. Database Query Optimization
Slow database queries can delay content rendering.
Identify Slow Queries
Enable Query Logging:
Edit /application/config/concrete.php:
return [
'debug' => [
'detail' => 'debug',
'display_errors' => true,
],
'database' => [
'queries' => [
'log' => true
]
]
];
View logs in /application/files/log/queries/
Solutions:
A. Optimize Page Version Queries
Remove old page versions:
Dashboard → System & Settings → Optimization → Automated Jobs
- Enable "Remove Old Page Versions"
- Configure to keep last 10 versions
- Run job
B. Add Database Indexes
For frequently queried custom attributes:
<?php
// In package controller or migration
$db = \Database::connection();
$db->executeQuery('CREATE INDEX idx_custom_attribute ON btCustomTable (attribute_column)');
?>
C. Use Pagination
For page lists:
<?php
$pageList = new \Concrete\Core\Page\PageList();
$pageList->setItemsPerPage(12); // Limit results
$pageList->setNamespace('pagination_namespace');
$paginator = $pageList->getPagination();
?>
7. Font Loading Optimization
Custom fonts can delay LCP if not optimized.
Font Loading Best Practices
A. Preload Fonts
<!-- In page template <head> -->
<link rel="preload" href="<?php echo $this->getThemePath(); ?>/fonts/main-font.woff2" as="font" type="font/woff2" crossorigin>
B. Use Font-Display Swap
@font-face {
font-family: 'CustomFont';
src: url('fonts/custom-font.woff2') format('woff2');
font-display: swap; /* Show fallback immediately */
font-weight: 400;
font-style: normal;
}
C. Limit Font Weights
Only load font weights you actually use:
/* Instead of loading 100-900, only load what you need */
@font-face {
font-family: 'CustomFont';
src: url('fonts/custom-font-regular.woff2') format('woff2');
font-weight: 400;
}
@font-face {
font-family: 'CustomFont';
src: url('fonts/custom-font-bold.woff2') format('woff2');
font-weight: 700;
}
8. Server-Side Optimization
Server configuration affects LCP.
Enable Gzip Compression
Apache (.htaccess):
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/json
</IfModule>
Nginx:
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/json;
Enable Browser Caching
Apache (.htaccess):
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "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"
ExpiresByType application/pdf "access plus 1 month"
</IfModule>
Use CDN
Configure CDN for static assets:
Dashboard → System & Settings → Files → File Storage Locations
- Add CDN location for public files
- Configure URL mapping
- Upload existing files to CDN
Testing & Monitoring
Test LCP
Tools:
- PageSpeed Insights - Lab and field data
- WebPageTest - Detailed waterfall
- Chrome DevTools - Local testing (Lighthouse)
- GTmetrix - Detailed reports
Test Multiple Pages:
- Homepage
- Blog posts
- Landing pages
- Form pages
Test Different Devices:
- Desktop
- Mobile
- Tablet
Monitor LCP Over Time
Chrome User Experience Report (CrUX):
- Real user data in PageSpeed Insights
- Track trends over 28 days
- Core Web Vitals report
- Shows pages failing LCP
- Impact on SEO
Quick Wins Checklist
Start here for immediate LCP improvements:
- Use Concrete CMS thumbnail system for all images
- Add explicit width/height to hero images
- Use
loading="eager"on LCP image - Enable full page caching
- Enable asset minification and combining
- Uninstall unused marketplace add-ons
- Use
font-display: swapfor custom fonts - Enable Gzip compression
- Configure opcache properly
- Remove old page versions
- Test with PageSpeed Insights
When to Hire a Developer
Consider hiring a Concrete CMS developer if:
- LCP consistently over 4 seconds after optimizations
- Complex custom theme needs optimization
- Multiple add-ons required but causing performance issues
- Need custom caching solution
- Database queries need optimization
- Server configuration needs expert tuning
Find Developers: Concrete CMS Marketplace
Next Steps
For general LCP optimization strategies, see LCP Optimization Guide.