Fix osCommerce LCP Issues | OpsBlu Docs

Fix osCommerce LCP Issues

Improve osCommerce LCP by compressing product images, enabling PHP opcode caching, and reducing legacy template includes.

Overview

Largest Contentful Paint (LCP) measures how quickly the main content of a page loads. Google considers LCP a critical metric for page experience and SEO ranking.

LCP Targets:

  • Good: < 2.5 seconds
  • Needs Improvement: 2.5 - 4.0 seconds
  • Poor: > 4.0 seconds

Check Your LCP

Method 1: PageSpeed Insights

1. Go to https://pagespeed.web.dev/
2. Enter your OSCommerce store URL
3. Check LCP score under "Diagnostics"

Method 2: Chrome DevTools

1. Open page in Chrome
2. Press F12 > Lighthouse tab
3. Click "Generate report"
4. Check LCP under "Performance"

Method 3: Web Vitals Extension

1. Install Web Vitals Chrome extension
2. Visit your store
3. Click extension to see real-time LCP

Common LCP Elements in OSCommerce

Typical LCP elements on OSCommerce pages:

  • Homepage: Hero banner image, featured product images
  • Product Pages: Main product image
  • Category Pages: First product images or banner
  • Text Content: Product descriptions, category headings

Diagnosis: Identify Your LCP Element

Using Chrome DevTools:

1. F12 > Performance tab
2. Click Record (circle icon)
3. Reload page
4. Stop recording
5. Look for "LCP" marker in timeline
6. Hover to see which element is LCP

Fix 1: Optimize Images

Images are the most common LCP element. Optimize them for faster loading.

Compress Images

Before uploading to OSCommerce:

# Use image compression tools:
# - TinyPNG (https://tinypng.com/)
# - ImageOptim (Mac)
# - Squoosh (https://squoosh.app/)

# Target sizes:
# Product images: < 100KB
# Banner images: < 200KB
# Thumbnails: < 30KB

Convert to Modern Formats

Use WebP for better compression:

<?php
// File: catalog/includes/functions/html_output.php

// Add WebP support function
function tep_image_webp($src, $alt = '', $width = '', $height = '', $parameters = '') {
  $webp_src = preg_replace('/\.(jpg|jpeg|png)$/i', '.webp', $src);

  if (file_exists($webp_src)) {
    return '<picture>
      <source srcset="' . $webp_src . '" type="image/webp">
      <img src="' . $src . '" alt="' . $alt . '" width="' . $width . '" height="' . $height . '" ' . $parameters . '>
    </picture>';
  } else {
    return tep_image($src, $alt, $width, $height, $parameters);
  }
}
?>

Serve Appropriately Sized Images

File: catalog/product_info.php

<?php
// Don't load huge images that will be displayed small

// BAD - Loading 2000x2000 image for 400px display
echo tep_image(DIR_WS_IMAGES . $product_info['products_image'], $product_info['products_name']);

// GOOD - Generate/use appropriately sized image
$image_size = 600; // Display size
echo tep_image(DIR_WS_IMAGES . $product_info['products_image'], $product_info['products_name'], $image_size, $image_size);
?>

Add Width and Height Attributes

Prevent layout shifts and speed up rendering:

<?php
// File: catalog/includes/functions/html_output.php

function tep_image($src, $alt = '', $width = '', $height = '', $parameters = '') {
  // Always include width and height
  if (!$width || !$height) {
    $image_path = DIR_FS_CATALOG . $src;
    if (file_exists($image_path)) {
      list($width, $height) = getimagesize($image_path);
    }
  }

  $image = '<img src="' . tep_output_string($src) . '" alt="' . tep_output_string($alt) . '"';

  if ($width) {
    $image .= ' width="' . tep_output_string($width) . '"';
  }

  if ($height) {
    $image .= ' height="' . tep_output_string($height) . '"';
  }

  if ($parameters) {
    $image .= ' ' . $parameters;
  }

  $image .= '>';

  return $image;
}
?>

Fix 2: Implement Lazy Loading

Don't load images that aren't visible initially.

Native Lazy Loading

File: catalog/includes/functions/html_output.php

<?php
function tep_image($src, $alt = '', $width = '', $height = '', $parameters = '', $lazy = true) {
  $image = '<img src="' . tep_output_string($src) . '" alt="' . tep_output_string($alt) . '"';

  if ($width) $image .= ' width="' . $width . '"';
  if ($height) $image .= ' height="' . $height . '"';

  // Add lazy loading for non-LCP images
  if ($lazy) {
    $image .= ' loading="lazy"';
  }

  if ($parameters) $image .= ' ' . $parameters;

  $image .= '>';

  return $image;
}
?>

Usage:

<?php
// Product page - main image should NOT be lazy loaded (it's LCP)
echo tep_image($main_image, $alt, 600, 600, '', false); // lazy = false

// Thumbnail images - should be lazy loaded
foreach ($thumbnails as $thumb) {
  echo tep_image($thumb, $alt, 100, 100, '', true); // lazy = true
}
?>

Lazy Load Below the Fold

<!-- Images in viewport: NO lazy loading -->
<img src="hero-banner.jpg" alt="Banner" width="1200" height="400">

<!-- Images below fold: YES lazy loading -->
<img src="product-1.jpg" alt="Product" width="300" height="300" loading="lazy">
<img src="product-2.jpg" alt="Product" width="300" height="300" loading="lazy">

Fix 3: Preload LCP Image

Tell the browser to load the LCP image as early as possible.

File: catalog/includes/header.php

<?php
// Identify LCP image per page type
$lcp_image = null;

// Homepage - hero banner
if (basename($_SERVER['PHP_SELF']) == 'index.php' && !isset($_GET['cPath'])) {
  $lcp_image = 'images/hero-banner.jpg';
}

// Product page - main product image
if (basename($_SERVER['PHP_SELF']) == 'product_info.php' && isset($product_info)) {
  $lcp_image = DIR_WS_IMAGES . $product_info['products_image'];
}

// Category page - first product or category banner
if (isset($_GET['cPath']) && isset($listing[0])) {
  $lcp_image = DIR_WS_IMAGES . $listing[0]['products_image'];
}

// Preload LCP image
if ($lcp_image) {
?>
<link rel="preload" as="image" href="<?php echo $lcp_image; ?>">
<?php
}
?>

Preload with fetchpriority

For modern browsers:

<link rel="preload" as="image" href="hero-banner.jpg" fetchpriority="high">

<!-- Or directly on img tag -->
<img src="hero-banner.jpg" fetchpriority="high" width="1200" height="400">

Fix 4: Optimize Server Response Time

Slow server = slow LCP.

Enable PHP OPcache

File: php.ini or contact hosting provider

opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60

Enable Database Query Caching

File: catalog/includes/configure.php

<?php
// Enable MySQL query cache (if available)
define('USE_PCONNECT', 'true'); // Persistent connections

// Or implement object caching
define('USE_CACHE', 'true');
define('CACHE_LIFETIME', 3600); // 1 hour
?>

Implement Page Caching

Cache generated pages to reduce server load:

<?php
// File: catalog/includes/application_top.php

// Simple page cache
$cache_file = 'cache/page_' . md5($_SERVER['REQUEST_URI']) . '.html';
$cache_time = 3600; // 1 hour

if (file_exists($cache_file) && (time() - filemtime($cache_file)) < $cache_time) {
  // Serve cached version
  readfile($cache_file);
  exit;
}

// Generate page normally
ob_start();

// ... rest of OSCommerce code ...

// At end of page:
// File: catalog/includes/application_bottom.php
$content = ob_get_contents();
file_put_contents($cache_file, $content);
ob_end_flush();
?>

Fix 5: Use a CDN

Serve static assets from a CDN for faster delivery.

Implement CDN for Images

File: catalog/includes/configure.php

<?php
// Define CDN URL
define('CDN_URL', 'https://cdn.yourstore.com/');

// Update image paths
define('DIR_WS_IMAGES', CDN_URL . 'images/');
define('DIR_WS_IMAGES_CATALOG', CDN_URL . 'images/catalog/');
?>
  • Cloudflare - Free tier available
  • BunnyCDN - Affordable, fast
  • CloudFront - AWS CDN
  • KeyCDN - Pay-as-you-go

Fix 6: Optimize CSS

Render-blocking CSS delays LCP.

Inline Critical CSS

File: catalog/includes/header.php

<head>
<!-- Inline critical CSS -->
<style>
/* Above-the-fold styles only */
body { margin: 0; font-family: Arial, sans-serif; }
.header { background: #fff; padding: 20px; }
.hero { width: 100%; height: 400px; }
.product-main { max-width: 600px; }
</style>

<!-- Defer non-critical CSS -->
<link rel="preload" href="stylesheet.css" as="style"
<noscript><link rel="stylesheet" href="stylesheet.css"></noscript>
</head>

Remove Unused CSS

Eliminate CSS not used on the page:

# Use PurgeCSS or similar tool
# https://purgecss.com/

# Analyze with Coverage tool:
# Chrome DevTools > More tools > Coverage
# See which CSS is unused

Minify CSS

<?php
// File: catalog/includes/header.php

// Use minified CSS in production
if (PRODUCTION_MODE) {
  $stylesheet = 'stylesheet.min.css';
} else {
  $stylesheet = 'stylesheet.css';
}
?>
<link rel="stylesheet" href="<?php echo $stylesheet; ?>">

Fix 7: Optimize Web Fonts

Web fonts can delay LCP if not loaded efficiently.

Use font-display: swap

File: CSS file

@font-face {
  font-family: 'CustomFont';
  src: url('fonts/customfont.woff2') format('woff2');
  font-display: swap; /* Show fallback font immediately */
}

Preload Critical Fonts

File: catalog/includes/header.php

<link rel="preload" href="fonts/mainfont.woff2" as="font" type="font/woff2" crossorigin>

Self-Host Google Fonts

Instead of loading from Google:

<!-- DON'T use Google CDN -->
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">

<!-- DO self-host fonts -->
<link rel="preload" href="fonts/roboto.woff2" as="font" type="font/woff2" crossorigin>
<style>
@font-face {
  font-family: 'Roboto';
  src: url('fonts/roboto.woff2') format('woff2');
  font-display: swap;
}
</style>

Fix 8: Reduce JavaScript Impact

JavaScript can block LCP rendering.

Defer Non-Critical JavaScript

File: catalog/includes/header.php

<!-- DON'T load JavaScript in head without defer -->
<script src="jquery.js"></script>

<!-- DO defer JavaScript -->
<script src="jquery.js" defer></script>

<!-- Or load at end of body -->
</body>
<script src="scripts.js"></script>
</html>

Load Analytics Asynchronously

<!-- GA4 already loads async -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>

<!-- GTM already loads async -->
<script>(function(w,d,s,l,i){...})(window,document,'script','dataLayer','GTM-XXXXXX');</script>

Fix 9: Upgrade Hosting

Sometimes the problem is hosting performance.

Signs You Need Better Hosting

  • Server response time > 600ms
  • Frequent downtime
  • Limited resources (CPU, RAM)
  • Old PHP version (< 7.4)
  • No SSD storage
  • Shared hosting with resource limits
  • VPS - More resources, better performance
  • Managed WordPress/PHP hosting - Optimized servers
  • Cloud hosting - AWS, Google Cloud, DigitalOcean
  • Dedicated server - Maximum performance

Testing Improvements

Before and After Comparison

1. Test before changes: https://pagespeed.web.dev/
2. Record LCP score
3. Implement fixes
4. Test after changes
5. Compare improvement

Real User Monitoring

Track actual user LCP:

<script>
new PerformanceObserver((list) => {
  const entries = list.getEntries();
  const lastEntry = entries[entries.length - 1];

  // Send to analytics
  gtag('event', 'web_vitals', {
    'event_category': 'Web Vitals',
    'event_label': 'LCP',
    'value': Math.round(lastEntry.renderTime || lastEntry.loadTime),
    'metric_value': Math.round(lastEntry.renderTime || lastEntry.loadTime)
  });
}).observe({type: 'largest-contentful-paint', buffered: true});
</script>

Quick Wins Checklist

Fastest improvements with biggest impact:

  • Compress and optimize all images
  • Add width/height to all images
  • Preload LCP image
  • Enable gzip/brotli compression
  • Use browser caching
  • Defer non-critical JavaScript
  • Minify CSS and JavaScript
  • Enable OPcache
  • Use CDN for images
  • Remove unused CSS/JS

Advanced Optimizations

HTTP/2 Push

Push LCP resources:

# .htaccess
<IfModule mod_http2.c>
  H2PushResource add css/stylesheet.css
  H2PushResource add images/hero-banner.jpg
</IfModule>

Adaptive Image Loading

Load different image sizes based on device:

<picture>
  <source media="(max-width: 640px)" srcset="hero-mobile.jpg">
  <source media="(max-width: 1024px)" srcset="hero-tablet.jpg">
  <img src="hero-desktop.jpg" alt="Hero" width="1200" height="400">
</picture>

Monitoring

Set up continuous monitoring:

1. Google Search Console - Core Web Vitals report
2. PageSpeed Insights - Regular tests
3. Real User Monitoring - Track actual users
4. Lighthouse CI - Automated testing

Next Steps

Additional Resources