Optimizing WordPress for Mobile Performance
Mobile users now account for over 60% of web traffic, making mobile performance critical for WordPress success. Mobile optimization goes beyond responsive design—it requires specific strategies for limited bandwidth, touch interactions, and smaller screens. This comprehensive guide covers everything from mobile-first development to advanced optimization techniques that ensure your WordPress site delivers exceptional mobile experiences.
Poor mobile performance directly impacts user engagement, with 53% of mobile users abandoning sites that take over 3 seconds to load. We'll explore practical techniques to achieve sub-second load times on mobile devices while maintaining rich functionality and visual appeal.
Table of Contents
- Mobile Performance Fundamentals
- Responsive Design Optimization
- Mobile-First Development
- Touch and Interaction Optimization
- Mobile-Specific Performance Techniques
- AMP Implementation
- Testing and Monitoring
Mobile Performance Fundamentals
Understanding Mobile Constraints
Mobile devices face unique challenges that impact performance:
// Mobile device constraints detector
class MobileConstraints {
constructor() {
this.constraints = {
network: this.detectNetworkType(),
cpu: this.estimateCPUPower(),
memory: this.getAvailableMemory(),
battery: this.getBatteryStatus(),
viewport: this.getViewportDimensions()
};
}
detectNetworkType() {
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
if (connection) {
return {
type: connection.effectiveType, // '4g', '3g', '2g', 'slow-2g'
downlink: connection.downlink, // Mbps
rtt: connection.rtt, // Round trip time in ms
saveData: connection.saveData // Data saver enabled
};
}
return { type: 'unknown' };
}
estimateCPUPower() {
// Estimate CPU power based on hardware concurrency
const cores = navigator.hardwareConcurrency || 2;
const isMobile = /Android|webOS|iPhone|iPad|iPod/i.test(navigator.userAgent);
return {
cores: cores,
estimated_power: isMobile ? 'low' : 'high',
recommendation: cores <= 4 ? 'reduce-animations' : 'full-experience'
};
}
adaptPerformance() {
const network = this.constraints.network;
if (network.type === '2g' || network.type === 'slow-2g' || network.saveData) {
return {
images: 'low-quality',
videos: 'disabled',
animations: 'reduced',
prefetch: false
};
} else if (network.type === '3g') {
return {
images: 'medium-quality',
videos: 'on-demand',
animations: 'simple',
prefetch: 'minimal'
};
}
return {
images: 'high-quality',
videos: 'auto-play',
animations: 'full',
prefetch: true
};
}
}
Mobile-Specific Performance Metrics
// Track mobile-specific metrics
class Mobile_Performance_Tracker {
public function __construct() {
add_action('wp_footer', [$this, 'inject_performance_tracking']);
}
public function inject_performance_tracking() {
if (!wp_is_mobile()) {
return;
}
?>
<script>
(function() {
// First Input Delay (FID) - Critical for mobile
let firstInputDelay = 0;
let firstInputTimeStamp = 0;
['click', 'touchstart', 'keydown'].forEach(event => {
addEventListener(event, (e) => {
if (!firstInputTimeStamp) {
firstInputDelay = Date.now() - e.timeStamp;
firstInputTimeStamp = e.timeStamp;
// Send to analytics
if (window.gtag) {
gtag('event', 'FID', {
'event_category': 'Web Vitals',
'value': Math.round(firstInputDelay)
});
}
}
}, { once: true, passive: true });
});
// Touch responsiveness
let touchStartTime;
document.addEventListener('touchstart', () => {
touchStartTime = performance.now();
}, { passive: true });
document.addEventListener('touchend', () => {
const touchDuration = performance.now() - touchStartTime;
if (touchDuration > 100) { // Slow touch response
console.warn('Slow touch response:', touchDuration + 'ms');
}
}, { passive: true });
// Viewport changes (orientation)
let lastOrientation = window.orientation;
window.addEventListener('orientationchange', () => {
const newOrientation = window.orientation;
// Track orientation changes
if (window.gtag) {
gtag('event', 'orientation_change', {
'from': lastOrientation,
'to': newOrientation
});
}
lastOrientation = newOrientation;
});
})();
</script>
<?php
}
}
new Mobile_Performance_Tracker();
Responsive Design Optimization
Optimized Responsive Images
// Advanced responsive image implementation
class Responsive_Image_Optimizer {
public function __construct() {
add_filter('wp_get_attachment_image_attributes', [$this, 'optimize_image_attributes'], 10, 3);
add_filter('the_content', [$this, 'optimize_content_images']);
add_action('wp_head', [$this, 'add_preconnect_headers']);
}
public function optimize_image_attributes($attributes, $attachment, $size) {
// Generate optimal srcset for mobile
$image_meta = wp_get_attachment_metadata($attachment->ID);
$upload_dir = wp_upload_dir();
$base_url = $upload_dir['baseurl'] . '/' . dirname($image_meta['file']);
$srcset = [];
$sizes = [
'thumbnail' => 150,
'medium' => 300,
'medium_large' => 768,
'large' => 1024,
'full' => $image_meta['width']
];
foreach ($sizes as $size_name => $width) {
if (isset($image_meta['sizes'][$size_name])) {
$srcset[] = $base_url . '/' . $image_meta['sizes'][$size_name]['file'] . ' ' . $width . 'w';
}
}
$attributes['srcset'] = implode(', ', $srcset);
// Mobile-optimized sizes attribute
$attributes['sizes'] = '(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw';
// Add loading lazy by default
$attributes['loading'] = 'lazy';
// Add aspect ratio for CLS prevention
if (isset($image_meta['width']) && isset($image_meta['height'])) {
$attributes['style'] = sprintf(
'aspect-ratio: %d / %d;',
$image_meta['width'],
$image_meta['height']
);
}
return $attributes;
}
public function optimize_content_images($content) {
// Process images in content
$content = preg_replace_callback(
'/<img([^>]+)>/i',
[$this, 'process_image_tag'],
$content
);
return $content;
}
private function process_image_tag($matches) {
$img_tag = $matches[0];
// Add loading="lazy" if not present
if (stripos($img_tag, 'loading=') === false) {
$img_tag = str_replace('<img', '<img loading="lazy"', $img_tag);
}
// Add decoding="async" for better performance
if (stripos($img_tag, 'decoding=') === false) {
$img_tag = str_replace('<img', '<img decoding="async"', $img_tag);
}
// Extract and optimize src
preg_match('/src=["\']([^"\']+)["\']/i', $img_tag, $src_matches);
if (!empty($src_matches[1])) {
$src = $src_matches[1];
// Convert to WebP if supported
if ($this->client_supports_webp()) {
$webp_src = $this->get_webp_url($src);
if ($webp_src) {
$img_tag = str_replace($src, $webp_src, $img_tag);
}
}
}
return $img_tag;
}
private function client_supports_webp() {
return isset($_SERVER['HTTP_ACCEPT']) &&
strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== false;
}
private function get_webp_url($image_url) {
// Convert image URL to WebP version
$pathinfo = pathinfo($image_url);
$webp_url = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '.webp';
// Check if WebP version exists
$upload_dir = wp_upload_dir();
$relative_path = str_replace($upload_dir['baseurl'], '', $webp_url);
$webp_path = $upload_dir['basedir'] . $relative_path;
if (file_exists($webp_path)) {
return $webp_url;
}
return false;
}
}
new Responsive_Image_Optimizer();
Mobile-Optimized CSS
/* Mobile-first CSS optimization */
/* Critical CSS for above-the-fold mobile content */
.critical-mobile {
/* Minimal layout styles */
display: flex;
flex-direction: column;
padding: 1rem;
/* System font stack for faster loading */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, sans-serif;
}
/* Responsive typography with fluid scaling */
:root {
--min-font-size: 16px;
--max-font-size: 20px;
--min-viewport: 320px;
--max-viewport: 1200px;
}
body {
font-size: clamp(
var(--min-font-size),
calc(var(--min-font-size) + (var(--max-font-size) - var(--min-font-size)) *
((100vw - var(--min-viewport)) / (var(--max-viewport) - var(--min-viewport)))),
var(--max-font-size)
);
/* Optimize for readability on mobile */
line-height: 1.6;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Touch-friendly interactive elements */
button, a, input, select, textarea {
min-height: 44px; /* Apple's HIG recommendation */
min-width: 44px;
padding: 0.75rem 1rem;
/* Prevent tap highlight on iOS */
-webkit-tap-highlight-color: transparent;
}
/* Optimize animations for mobile */
@media (prefers-reduced-motion: no-preference) {
.animate {
animation: slideIn 0.3s ease-out;
/* Use GPU acceleration */
will-change: transform;
transform: translateZ(0);
}
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(1rem);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Responsive grid optimized for mobile */
.mobile-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
/* Contain layout shifts */
contain: layout style;
}
/* Mobile-specific media queries */
@media (max-width: 768px) {
/* Hide non-essential elements */
.desktop-only {
display: none !important;
}
/* Optimize spacing for touch */
.mobile-spacing {
padding: 1rem;
margin-bottom: 1rem;
}
/* Full-width elements on mobile */
.mobile-full {
width: 100%;
max-width: 100%;
margin-left: -1rem;
margin-right: -1rem;
padding-left: 1rem;
padding-right: 1rem;
}
}
/* High DPI display optimization */
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
/* Use higher quality images for retina displays */
.retina-image {
background-image: url('[email protected]');
background-size: contain;
}
}
Mobile-First Development
Mobile-First WordPress Theme Structure
// Mobile-first theme functions
class Mobile_First_Theme {
public function __construct() {
add_action('after_setup_theme', [$this, 'setup_mobile_features']);
add_action('wp_enqueue_scripts', [$this, 'load_mobile_assets']);
add_filter('body_class', [$this, 'add_mobile_body_classes']);
}
public function setup_mobile_features() {
// Mobile-specific image sizes
add_image_size('mobile-featured', 640, 360, true);
add_image_size('mobile-thumbnail', 320, 180, true);
// Enable responsive embeds
add_theme_support('responsive-embeds');
// Disable Gutenberg block styles on mobile
if (wp_is_mobile()) {
add_filter('should_load_separate_core_block_assets', '__return_true');
}
}
public function load_mobile_assets() {
// Load different assets based on device
if (wp_is_mobile()) {
// Mobile-specific stylesheet
wp_enqueue_style(
'mobile-styles',
get_template_directory_uri() . '/assets/css/mobile.min.css',
[],
'1.0.0'
);
// Lighter JavaScript bundle for mobile
wp_enqueue_script(
'mobile-scripts',
get_template_directory_uri() . '/assets/js/mobile.min.js',
[],
'1.0.0',
true
);
// Dequeue heavy desktop scripts
wp_dequeue_script('heavy-slider');
wp_dequeue_script('desktop-animations');
} else {
// Desktop assets
wp_enqueue_style(
'desktop-styles',
get_template_directory_uri() . '/assets/css/desktop.min.css',
[],
'1.0.0'
);
}
// Progressive enhancement script
wp_add_inline_script('mobile-scripts', $this->get_progressive_enhancement_script());
}
private function get_progressive_enhancement_script() {
return "
// Progressive enhancement based on device capabilities
(function() {
const enhance = {
init: function() {
// Check for touch support
if ('ontouchstart' in window) {
document.documentElement.classList.add('touch');
}
// Check connection speed
if ('connection' in navigator) {
const connection = navigator.connection;
if (connection.effectiveType === '4g' && !connection.saveData) {
this.loadEnhancements();
}
}
// Intersection Observer for lazy loading
if ('IntersectionObserver' in window) {
this.setupLazyLoading();
}
},
loadEnhancements: function() {
// Load additional features for capable devices
const script = document.createElement('script');
script.src = '" . get_template_directory_uri() . "/assets/js/enhancements.js';
document.body.appendChild(script);
},
setupLazyLoading: function() {
const images = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
imageObserver.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
}
};
enhance.init();
})();
";
}
public function add_mobile_body_classes($classes) {
if (wp_is_mobile()) {
$classes[] = 'is-mobile';
// Detect specific mobile OS
$user_agent = $_SERVER['HTTP_USER_AGENT'];
if (strpos($user_agent, 'iPhone') !== false || strpos($user_agent, 'iPad') !== false) {
$classes[] = 'ios-device';
} elseif (strpos($user_agent, 'Android') !== false) {
$classes[] = 'android-device';
}
}
return $classes;
}
}
new Mobile_First_Theme();
Conditional Loading for Mobile
// Smart resource loading based on device
class Mobile_Resource_Manager {
public function __construct() {
add_action('init', [$this, 'setup_conditional_loading']);
add_filter('script_loader_tag', [$this, 'add_async_defer_attributes'], 10, 2);
}
public function setup_conditional_loading() {
if (!wp_is_mobile()) {
return;
}
// Disable emojis on mobile
remove_action('wp_head', 'print_emoji_detection_script', 7);
remove_action('wp_print_styles', 'print_emoji_styles');
// Disable oEmbed on mobile
remove_action('wp_head', 'wp_oembed_add_discovery_links');
remove_action('wp_head', 'wp_oembed_add_host_js');
// Limit post revisions on mobile editing
if (is_admin()) {
add_filter('wp_revisions_to_keep', function($num, $post) {
return 5; // Keep only 5 revisions
}, 10, 2);
}
}
public function add_async_defer_attributes($tag, $handle) {
// Mobile-specific async/defer loading
$async_scripts = ['mobile-analytics', 'social-sharing'];
$defer_scripts = ['comment-reply', 'wp-embed'];
if (wp_is_mobile()) {
if (in_array($handle, $async_scripts)) {
return str_replace(' src', ' async src', $tag);
}
if (in_array($handle, $defer_scripts)) {
return str_replace(' src', ' defer src', $tag);
}
}
return $tag;
}
}
new Mobile_Resource_Manager();
Touch and Interaction Optimization
Touch-Optimized Navigation
// Mobile navigation with touch gestures
class TouchNavigation {
constructor() {
this.nav = document.querySelector('.mobile-nav');
this.touchStartX = 0;
this.touchStartY = 0;
this.isMenuOpen = false;
this.init();
}
init() {
// Hamburger menu
const menuToggle = document.querySelector('.menu-toggle');
menuToggle.addEventListener('click', () => this.toggleMenu());
// Touch gestures
document.addEventListener('touchstart', (e) => this.handleTouchStart(e), { passive: true });
document.addEventListener('touchmove', (e) => this.handleTouchMove(e), { passive: false });
// Improve tap responsiveness
this.fastClick();
}
toggleMenu() {
this.isMenuOpen = !this.isMenuOpen;
this.nav.classList.toggle('is-open');
document.body.classList.toggle('menu-open');
// Trap focus when menu is open
if (this.isMenuOpen) {
this.trapFocus();
}
}
handleTouchStart(e) {
this.touchStartX = e.touches[0].clientX;
this.touchStartY = e.touches[0].clientY;
}
handleTouchMove(e) {
if (!this.touchStartX || !this.touchStartY) {
return;
}
const touchEndX = e.touches[0].clientX;
const touchEndY = e.touches[0].clientY;
const deltaX = touchEndX - this.touchStartX;
const deltaY = touchEndY - this.touchStartY;
// Detect horizontal swipe
if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 50) {
if (deltaX > 0 && !this.isMenuOpen) {
// Swipe right - open menu
this.toggleMenu();
} else if (deltaX < 0 && this.isMenuOpen) {
// Swipe left - close menu
this.toggleMenu();
}
// Prevent scrolling during swipe
e.preventDefault();
}
// Reset values
this.touchStartX = null;
this.touchStartY = null;
}
fastClick() {
// Remove 300ms delay on touch devices
let touchStartTime;
let touchStartX;
let touchStartY;
document.addEventListener('touchstart', (e) => {
touchStartTime = Date.now();
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
}, { passive: true });
document.addEventListener('touchend', (e) => {
const touchEndTime = Date.now();
const touchEndX = e.changedTouches[0].clientX;
const touchEndY = e.changedTouches[0].clientY;
// Check if it's a tap (not a swipe or long press)
const timeDiff = touchEndTime - touchStartTime;
const distX = Math.abs(touchEndX - touchStartX);
const distY = Math.abs(touchEndY - touchStartY);
if (timeDiff < 200 && distX < 10 && distY < 10) {
// Trigger click immediately
const clickEvent = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
e.target.dispatchEvent(clickEvent);
e.preventDefault();
}
}, { passive: false });
}
trapFocus() {
const focusableElements = this.nav.querySelectorAll(
'a[href], button, input, textarea, select, [tabindex]:not([tabindex="-1"])'
);
const firstFocusable = focusableElements[0];
const lastFocusable = focusableElements[focusableElements.length - 1];
this.nav.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey) {
if (document.activeElement === firstFocusable) {
lastFocusable.focus();
e.preventDefault();
}
} else {
if (document.activeElement === lastFocusable) {
firstFocusable.focus();
e.preventDefault();
}
}
}
if (e.key === 'Escape') {
this.toggleMenu();
}
});
}
}
// Initialize on DOM ready
document.addEventListener('DOMContentLoaded', () => {
new TouchNavigation();
});
Mobile Form Optimization
// Mobile-optimized form handling
class Mobile_Form_Optimizer {
public function __construct() {
add_filter('comment_form_defaults', [$this, 'optimize_comment_form']);
add_action('wp_footer', [$this, 'add_form_enhancements']);
}
public function optimize_comment_form($defaults) {
if (!wp_is_mobile()) {
return $defaults;
}
// Mobile-optimized form fields
$defaults['fields']['author'] = '<p class="comment-form-author">' .
'<input id="author" name="author" type="text" ' .
'placeholder="' . __('Your Name *') . '" ' .
'autocomplete="name" ' .
'inputmode="text" ' .
'required /></p>';
$defaults['fields']['email'] = '<p class="comment-form-email">' .
'<input id="email" name="email" type="email" ' .
'placeholder="' . __('Your Email *') . '" ' .
'autocomplete="email" ' .
'inputmode="email" ' .
'required /></p>';
$defaults['fields']['url'] = '<p class="comment-form-url">' .
'<input id="url" name="url" type="url" ' .
'placeholder="' . __('Website') . '" ' .
'autocomplete="url" ' .
'inputmode="url" /></p>';
// Simplified mobile layout
$defaults['comment_field'] = '<p class="comment-form-comment">' .
'<textarea id="comment" name="comment" ' .
'placeholder="' . __('Your Comment *') . '" ' .
'rows="4" ' .
'required></textarea></p>';
return $defaults;
}
public function add_form_enhancements() {
if (!wp_is_mobile()) {
return;
}
?>
<script>
// Auto-resize textareas
document.querySelectorAll('textarea').forEach(textarea => {
textarea.style.height = 'auto';
textarea.addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = this.scrollHeight + 'px';
});
});
// Smooth scroll to form errors
const forms = document.querySelectorAll('form');
forms.forEach(form => {
form.addEventListener('invalid', (e) => {
e.preventDefault();
const firstError = form.querySelector(':invalid');
if (firstError) {
firstError.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
firstError.focus();
}
}, true);
});
// Improve number input on mobile
document.querySelectorAll('input[type="number"]').forEach(input => {
// Add increment/decrement buttons
const wrapper = document.createElement('div');
wrapper.className = 'number-input-wrapper';
input.parentNode.insertBefore(wrapper, input);
wrapper.appendChild(input);
const decrementBtn = document.createElement('button');
decrementBtn.textContent = '-';
decrementBtn.type = 'button';
decrementBtn.className = 'number-decrement';
decrementBtn.addEventListener('click', () => {
input.stepDown();
input.dispatchEvent(new Event('change'));
});
const incrementBtn = document.createElement('button');
incrementBtn.textContent = '+';
incrementBtn.type = 'button';
incrementBtn.className = 'number-increment';
incrementBtn.addEventListener('click', () => {
input.stepUp();
input.dispatchEvent(new Event('change'));
});
wrapper.insertBefore(decrementBtn, input);
wrapper.appendChild(incrementBtn);
});
</script>
<style>
/* Mobile form styles */
.number-input-wrapper {
display: flex;
align-items: center;
}
.number-decrement,
.number-increment {
width: 44px;
height: 44px;
font-size: 20px;
border: 1px solid #ddd;
background: #f5f5f5;
cursor: pointer;
}
input[type="number"] {
-moz-appearance: textfield;
text-align: center;
margin: 0 5px;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
</style>
<?php
}
}
new Mobile_Form_Optimizer();
Mobile-Specific Performance Techniques
Adaptive Loading Strategy
// Adaptive loading based on device capabilities
class AdaptiveLoader {
constructor() {
this.networkInfo = this.getNetworkInfo();
this.deviceMemory = navigator.deviceMemory || 4;
this.hardwareConcurrency = navigator.hardwareConcurrency || 2;
this.init();
}
getNetworkInfo() {
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
return {
type: connection?.effectiveType || '4g',
saveData: connection?.saveData || false,
downlink: connection?.downlink || 10,
rtt: connection?.rtt || 50
};
}
init() {
// Determine quality level
const quality = this.determineQuality();
// Apply adaptive strategies
this.adaptImages(quality);
this.adaptVideos(quality);
this.adaptFonts(quality);
this.adaptAnimations(quality);
}
determineQuality() {
// Score based on device capabilities
let score = 0;
// Network score (0-4)
const networkScores = { '4g': 4, '3g': 2, '2g': 1, 'slow-2g': 0 };
score += networkScores[this.networkInfo.type] || 2;
// Memory score (0-4)
score += Math.min(this.deviceMemory / 2, 4);
// CPU score (0-4)
score += Math.min(this.hardwareConcurrency / 2, 4);
// Data saver penalty
if (this.networkInfo.saveData) {
score = Math.floor(score / 2);
}
// Determine quality level
if (score >= 10) return 'high';
if (score >= 6) return 'medium';
return 'low';
}
adaptImages(quality) {
const images = document.querySelectorAll('img[data-adaptive]');
images.forEach(img => {
const sources = {
high: img.dataset.srcHigh || img.dataset.src,
medium: img.dataset.srcMedium || img.dataset.srcLow,
low: img.dataset.srcLow
};
// Set appropriate source
img.src = sources[quality];
// Adjust loading strategy
if (quality === 'low') {
img.loading = 'lazy';
} else if (quality === 'high') {
// Preload critical images
if (img.dataset.critical) {
const link = document.createElement('link');
link.rel = 'preload';
link.as = 'image';
link.href = img.src;
document.head.appendChild(link);
}
}
});
}
adaptVideos(quality) {
const videos = document.querySelectorAll('video');
videos.forEach(video => {
if (quality === 'low') {
// Replace with poster image
const poster = video.poster;
if (poster) {
const img = document.createElement('img');
img.src = poster;
img.alt = 'Video placeholder';
img.className = 'video-placeholder';
img.addEventListener('click', () => {
// Load video on demand
video.style.display = 'block';
img.style.display = 'none';
video.play();
});
video.parentNode.insertBefore(img, video);
video.style.display = 'none';
}
} else if (quality === 'medium') {
// Disable autoplay
video.removeAttribute('autoplay');
video.preload = 'metadata';
}
});
}
adaptFonts(quality) {
if (quality === 'low') {
// Use system fonts only
document.documentElement.style.setProperty(
'--font-family',
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
);
} else if (quality === 'medium') {
// Load subset fonts
const link = document.querySelector('link[href*="fonts.googleapis"]');
if (link) {
link.href = link.href.replace('&display=swap', '&display=optional');
}
}
}
adaptAnimations(quality) {
if (quality === 'low') {
// Disable all animations
const style = document.createElement('style');
style.textContent = `
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
`;
document.head.appendChild(style);
} else if (quality === 'medium') {
// Reduce animation complexity
document.documentElement.classList.add('reduce-motion');
}
}
}
// Initialize adaptive loading
if ('connection' in navigator || 'deviceMemory' in navigator) {
new AdaptiveLoader();
}
Service Worker for Mobile
// Mobile-optimized service worker
const CACHE_NAME = 'mobile-cache-v1';
const OFFLINE_URL = '/offline.html';
// Mobile-specific caching strategy
const mobileAssets = [
'/',
'/wp-content/themes/mobile/style.css',
'/wp-content/themes/mobile/mobile.js',
OFFLINE_URL
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(mobileAssets);
})
);
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
})
);
self.clients.claim();
});
self.addEventListener('fetch', (event) => {
// Network-first for HTML
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request)
.then((response) => {
// Cache successful responses
if (response.status === 200) {
const responseToCache = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseToCache);
});
}
return response;
})
.catch(() => {
// Serve offline page
return caches.match(OFFLINE_URL);
})
);
return;
}
// Cache-first for assets
event.respondWith(
caches.match(event.request).then((response) => {
if (response) {
// Update cache in background
event.waitUntil(
fetch(event.request).then((response) => {
if (response.status === 200) {
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, response);
});
}
}).catch(() => {})
);
return response;
}
return fetch(event.request).then((response) => {
// Don't cache non-successful responses
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
const responseToCache = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseToCache);
});
return response;
});
})
);
});
// Background sync for mobile
self.addEventListener('sync', (event) => {
if (event.tag === 'sync-comments') {
event.waitUntil(syncComments());
}
});
async function syncComments() {
const db = await openDB();
const tx = db.transaction('pending-comments', 'readonly');
const comments = await tx.objectStore('pending-comments').getAll();
for (const comment of comments) {
try {
await fetch('/wp-comments-post.php', {
method: 'POST',
body: new URLSearchParams(comment)
});
// Remove from pending
const deleteTx = db.transaction('pending-comments', 'readwrite');
await deleteTx.objectStore('pending-comments').delete(comment.id);
} catch (error) {
console.error('Failed to sync comment:', error);
}
}
}
AMP Implementation
WordPress AMP Setup
// AMP implementation for WordPress
class WordPress_AMP_Handler {
public function __construct() {
add_action('init', [$this, 'setup_amp_support']);
add_filter('amp_post_template_data', [$this, 'customize_amp_template']);
add_action('amp_post_template_css', [$this, 'amp_custom_styles']);
}
public function setup_amp_support() {
// Add AMP support for post types
add_post_type_support('post', 'amp');
add_post_type_support('page', 'amp');
// Custom AMP endpoints
add_rewrite_endpoint('amp', EP_PERMALINK);
}
public function customize_amp_template($data) {
// Add custom data to AMP template
$data['site_icon_url'] = get_site_icon_url();
$data['nav_menu'] = $this->get_amp_menu();
return $data;
}
public function amp_custom_styles() {
?>
/* AMP Custom Styles */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
line-height: 1.6;
padding: 1rem;
}
.amp-wp-header {
background-color: #0073aa;
color: white;
padding: 1rem;
text-align: center;
}
.amp-wp-article-content img {
max-width: 100%;
height: auto;
}
/* Mobile-optimized typography */
.amp-wp-article-content {
font-size: 18px;
line-height: 1.8;
}
/* Touch-friendly links */
a {
color: #0073aa;
text-decoration: none;
padding: 0.25rem;
margin: -0.25rem;
}
/* Optimized lists */
ul, ol {
padding-left: 1.5rem;
}
/* Code blocks */
pre {
overflow-x: auto;
background: #f5f5f5;
padding: 1rem;
border-radius: 4px;
}
<?php
}
private function get_amp_menu() {
// Generate AMP-compatible menu
$menu_items = wp_get_nav_menu_items('primary');
$amp_menu = '<nav class="amp-nav"><ul>';
foreach ($menu_items as $item) {
$amp_menu .= sprintf(
'<li><a href="%s">%s</a></li>',
esc_url($item->url),
esc_html($item->title)
);
}
$amp_menu .= '</ul></nav>';
return $amp_menu;
}
}
// AMP content filter
add_filter('the_content', function($content) {
if (!function_exists('is_amp_endpoint') || !is_amp_endpoint()) {
return $content;
}
// Convert images to amp-img
$content = preg_replace_callback(
'/<img([^>]+)>/i',
function($matches) {
preg_match('/src=["\']([^"\']+)["\']/i', $matches[1], $src);
preg_match('/width=["\'](\d+)["\']/i', $matches[1], $width);
preg_match('/height=["\'](\d+)["\']/i', $matches[1], $height);
preg_match('/alt=["\']([^"\']+)["\']/i', $matches[1], $alt);
$amp_img = sprintf(
'<amp-img src="%s" width="%s" height="%s" alt="%s" layout="responsive"></amp-img>',
esc_url($src[1] ?? ''),
esc_attr($width[1] ?? '800'),
esc_attr($height[1] ?? '600'),
esc_attr($alt[1] ?? '')
);
return $amp_img;
},
$content
);
// Convert iframes to amp-iframe
$content = preg_replace_callback(
'/<iframe([^>]+)>/i',
function($matches) {
preg_match('/src=["\']([^"\']+)["\']/i', $matches[1], $src);
preg_match('/width=["\'](\d+)["\']/i', $matches[1], $width);
preg_match('/height=["\'](\d+)["\']/i', $matches[1], $height);
// YouTube embeds
if (strpos($src[1], 'youtube.com') !== false) {
preg_match('/embed\/([a-zA-Z0-9_-]+)/', $src[1], $video_id);
return sprintf(
'<amp-youtube data-videoid="%s" width="%s" height="%s" layout="responsive"></amp-youtube>',
esc_attr($video_id[1] ?? ''),
esc_attr($width[1] ?? '800'),
esc_attr($height[1] ?? '450')
);
}
// Generic iframe
return sprintf(
'<amp-iframe src="%s" width="%s" height="%s" layout="responsive" sandbox="allow-scripts allow-same-origin"></amp-iframe>',
esc_url($src[1] ?? ''),
esc_attr($width[1] ?? '800'),
esc_attr($height[1] ?? '600')
);
},
$content
);
return $content;
});
new WordPress_AMP_Handler();
Testing and Monitoring
Mobile Performance Testing
// Mobile performance testing framework
class Mobile_Performance_Tester {
private $test_results = [];
public function run_tests() {
$this->test_results = [
'page_speed' => $this->test_page_speed(),
'mobile_usability' => $this->test_mobile_usability(),
'core_web_vitals' => $this->test_core_web_vitals(),
'touch_targets' => $this->test_touch_targets(),
'viewport_config' => $this->test_viewport_configuration()
];
return $this->generate_report();
}
private function test_page_speed() {
// Simulate mobile network conditions
$start_time = microtime(true);
// Test critical resources
$critical_resources = [
home_url() => 'Homepage',
get_permalink(get_option('page_for_posts')) => 'Blog page',
get_permalink(wc_get_page_id('shop')) => 'Shop page'
];
$results = [];
foreach ($critical_resources as $url => $name) {
$response = wp_remote_get($url, [
'timeout' => 10,
'user-agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15'
]);
if (!is_wp_error($response)) {
$body = wp_remote_retrieve_body($response);
$size = strlen($body) / 1024; // KB
$results[$name] = [
'size' => round($size, 2) . ' KB',
'load_time' => round(microtime(true) - $start_time, 2) . 's',
'status' => $size < 100 ? 'good' : ($size < 300 ? 'needs-improvement' : 'poor')
];
}
}
return $results;
}
private function test_mobile_usability() {
$issues = [];
// Check viewport meta tag
$viewport = get_option('viewport_meta_tag');
if (!$viewport || strpos($viewport, 'width=device-width') === false) {
$issues[] = 'Missing or incorrect viewport meta tag';
}
// Check font sizes
$theme_styles = file_get_contents(get_stylesheet_directory() . '/style.css');
if (preg_match_all('/font-size:\s*(\d+)px/i', $theme_styles, $matches)) {
foreach ($matches[1] as $size) {
if (intval($size) < 16) {
$issues[] = "Font size {$size}px is too small for mobile";
break;
}
}
}
// Check tap target sizes
if (preg_match_all('/(button|a)\s*\{[^}]*height:\s*(\d+)px/i', $theme_styles, $matches)) {
foreach ($matches[2] as $height) {
if (intval($height) < 44) {
$issues[] = "Tap target height {$height}px is too small";
break;
}
}
}
return empty($issues) ? ['status' => 'good'] : ['status' => 'issues', 'issues' => $issues];
}
private function test_core_web_vitals() {
// Simulate Core Web Vitals measurement
return [
'lcp' => [
'value' => 2.3,
'status' => 'good',
'recommendation' => 'Optimize largest image loading'
],
'fid' => [
'value' => 85,
'status' => 'good',
'recommendation' => 'Continue monitoring JavaScript execution'
],
'cls' => [
'value' => 0.08,
'status' => 'good',
'recommendation' => 'Add size attributes to all images'
]
];
}
private function generate_report() {
$overall_score = $this->calculate_overall_score();
return [
'score' => $overall_score,
'grade' => $this->get_grade($overall_score),
'test_results' => $this->test_results,
'recommendations' => $this->generate_recommendations(),
'timestamp' => current_time('mysql')
];
}
private function calculate_overall_score() {
$scores = [
'page_speed' => 30,
'mobile_usability' => 25,
'core_web_vitals' => 25,
'touch_targets' => 10,
'viewport_config' => 10
];
$total = 0;
foreach ($scores as $test => $weight) {
if (isset($this->test_results[$test]['status'])) {
$status = $this->test_results[$test]['status'];
$score = $status === 'good' ? 1 : ($status === 'needs-improvement' ? 0.5 : 0);
$total += $score * $weight;
}
}
return round($total);
}
private function get_grade($score) {
if ($score >= 90) return 'A';
if ($score >= 80) return 'B';
if ($score >= 70) return 'C';
if ($score >= 60) return 'D';
return 'F';
}
private function generate_recommendations() {
$recommendations = [];
foreach ($this->test_results as $test => $result) {
if (isset($result['status']) && $result['status'] !== 'good') {
switch ($test) {
case 'page_speed':
$recommendations[] = 'Implement lazy loading for images and videos';
$recommendations[] = 'Minify CSS and JavaScript files';
break;
case 'mobile_usability':
if (isset($result['issues'])) {
$recommendations = array_merge($recommendations, $result['issues']);
}
break;
case 'core_web_vitals':
foreach ($result as $metric => $data) {
if (isset($data['recommendation'])) {
$recommendations[] = $data['recommendation'];
}
}
break;
}
}
}
return array_unique($recommendations);
}
}
// Run mobile performance test
$tester = new Mobile_Performance_Tester();
$report = $tester->run_tests();
Next Steps
After implementing mobile optimization strategies:
- Monitor Real User Metrics: Use tools like Google Analytics and Search Console to track mobile performance
- Test on Real Devices: Don't rely solely on emulators—test on actual mobile devices
- Implement Progressive Web App Features: Consider adding PWA capabilities for app-like experiences
- Optimize for Core Web Vitals: Focus on mobile-specific CWV improvements
For more performance optimization strategies, explore our complete WordPress Performance Optimization guide.
Last updated: July 12, 2025