Skip to main content
WP HealthKit

WordPress Plugin Performance Budgets and Core Web Vitals

July 8, 202618 min readPerformanceBy Jamie

WordPress plugins have become increasingly complex, and with that complexity comes responsibility. A single poorly-optimized plugin can degrade site performance dramatically, hurting user experience and search rankings. However, most plugin developers lack systematic ways to track and control performance impact. WordPress plugin performance budgets—targets for resource usage like CSS, JavaScript, and HTTP requests—combined with Core Web Vitals measurement, create accountability for performance. By establishing clear performance budgets and testing against them continuously, developers ensure their plugins enhance rather than degrade site performance.

Table of Contents

  1. Understanding Performance Budgets
  2. Setting Realistic Plugin Budgets
  3. Measuring Core Web Vitals Impact
  4. Webpack and Build Tool Budgets
  5. Lighthouse CI Integration
  6. Detecting Performance Regressions
  7. Optimization Techniques
  8. Frequently Asked Questions

A WordPress plugin performance budget is a commitment to maintain reasonable resource usage. Just as you wouldn't allow code to grow indefinitely, you shouldn't allow CSS or JavaScript bundles to grow without limits. Performance budgets force deliberate decisions about what features are worth the performance cost and drive prioritization of optimization.

Understanding Performance Budgets

Performance budgets quantify acceptable resource usage for plugins. They answer: How much CSS is reasonable? How many HTTP requests? How much JavaScript? What should page load time increase be?

There are multiple budget types:

Size-based budgets: Maximum file sizes for assets

JavaScript (gzipped): 50 KB
CSS (gzipped): 30 KB
Images: 200 KB total
Fonts: 50 KB total

Request-based budgets: Maximum HTTP requests per page load

Total additional requests: 3
Font requests: 1
Image requests: 2

Timing budgets: Maximum performance impact

Time to Interactive increase: +500ms
Largest Contentful Paint increase: +200ms
Cumulative Layout Shift: +0.1
First Input Delay: +100ms

Network budgets: Resource constraints for different connection speeds

Slow 4G (1.6 Mbps): +2 seconds
Fast 4G (4 Mbps): +1 second
WiFi: +0.5 seconds

The WordPress plugin performance budget mindset means treating performance as a first-class concern alongside functionality. A feature that requires 500 KB of JavaScript is less desirable than one that requires 50 KB, even if the larger version has more capabilities.

Setting Realistic Plugin Budgets

Budgets must be realistic for the plugin's functionality while still encouraging optimization. Performance budgets are targets that guide development and prevent performance regression. They should challenge the team to optimize but not be impossible to achieve. Unrealistic budgets that are consistently exceeded lose credibility and stop being useful for guiding decisions. Similarly, loose budgets that are always under-budget provide no guidance for optimization trade-offs. The sweet spot is budgets that are about 10-15% lower than current measured performance, creating achievable targets that drive meaningful optimization. For new plugins, base budgets on similar existing plugins or industry standards for your plugin category. As plugins mature and feature sets evolve, budgets should evolve too. Regular review ensures budgets remain relevant and continue driving optimization efforts rather than becoming outdated constraints.

Start by measuring your current plugin's resource usage:

# Analyze CSS bundle size
wc -c dist/plugin-styles.min.css
# Output: 45000 bytes = 45 KB

# Analyze JavaScript bundle size
wc -c dist/plugin-scripts.min.js
# Output: 120000 bytes = 120 KB

# Count HTTP requests
curl -s https://example.com/wp-admin/admin.php?page=my-plugin | \
  grep -o '<link\|<script\|<img' | wc -l
# Output: 15 requests

Use these measurements to set initial budgets that are slightly lower than current usage, creating room for optimization:

{
  "performance": {
    "assets": {
      "javascript": {
        "budget": 100,
        "unit": "KB",
        "gzipped": true
      },
      "stylesheets": {
        "budget": 35,
        "unit": "KB",
        "gzipped": true
      },
      "images": {
        "budget": 180,
        "unit": "KB"
      }
    },
    "requests": {
      "total": 12,
      "scripts": 3,
      "styles": 2,
      "images": 4,
      "fonts": 2
    }
  }
}

Document why these budgets matter:

# Performance Budget Rationale

## JavaScript Budget: 100 KB (gzipped)
- Admin interface: 40 KB
- Settings panels: 30 KB
- Dashboard widgets: 20 KB
- Overhead: 10 KB

At typical WordPress hosting speeds (500 Mbps), 100 KB JavaScript = ~200ms additional load time

## CSS Budget: 35 KB (gzipped)
- Layout styles: 15 KB
- Component styles: 15 KB
- Responsive overrides: 5 KB

## Total Request Budget: 12 additional requests
- Current WP admin baseline: ~30 requests
- Our plugin adds: 12 requests (40% increase)
- Target sites: 15 second page load maximum

Create budgets for different contexts:

// webpack.config.js with performance budgets

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: __dirname + '/dist'
  },
  performance: {
    // Warn when assets exceed these sizes
    hints: 'warning',
    maxAssetSize: 100000,      // 100 KB
    maxEntrypointSize: 100000  // 100 KB
  },
  // ... rest of config
};

// Split budgets by build target
const performanceBudgets = {
  development: {
    javascript: 500, // Higher in dev, lower in prod
    css: 200
  },
  production: {
    javascript: 100,
    css: 35
  }
};

module.exports = {
  mode: process.env.NODE_ENV || 'development',
  performance: {
    hints: 'warning',
    maxAssetSize: performanceBudgets[process.env.NODE_ENV].javascript * 1000,
    maxEntrypointSize: performanceBudgets[process.env.NODE_ENV].javascript * 1000
  }
};

Measuring Core Web Vitals Impact

Core Web Vitals are Google's key metrics for user experience: LCP (Largest Contentful Paint), FID (First Input Delay), and CLS (Cumulative Layout Shift). Your plugin impacts these metrics. Google officially uses these metrics for search rankings, making them critical business metrics for WordPress site owners. When plugins degrade Core Web Vitals, they directly impact the site's search visibility. This creates a powerful incentive for plugin developers to optimize their code. Many site owners choose plugins based on performance characteristics, making plugins that preserve or improve Core Web Vitals more marketable. Understanding how your plugin affects each metric allows you to implement targeted optimizations. Some optimizations improve multiple metrics simultaneously, while others trade one metric for another. The goal is understanding these trade-offs so you make conscious decisions rather than accidentally degrading performance. Measurement requires both synthetic testing (running Lighthouse on controlled environments) and real-user monitoring (analyzing actual visitor data). Synthetic testing catches issues before they affect users, while real-user monitoring reveals whether optimizations actually work in production with real visitor patterns.

Measure your plugin's impact on each vital:

Largest Contentful Paint (LCP): Time for largest visible content element to render. Target: < 2.5 seconds

// Measure LCP impact in your plugin
const observer = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  const lastEntry = entries[entries.length - 1];
  
  console.log('LCP:', lastEntry.renderTime || lastEntry.loadTime);
  
  // If your plugin loads after LCP, it impacted the metric
  if (lastEntry.element?.classList?.contains('my-plugin-element')) {
    console.warn('Plugin element affected LCP');
  }
});

observer.observe({entryTypes: ['largest-contentful-paint']});

Optimize LCP by deferring plugin rendering:

// WordPress: Load critical plugin content inline, defer heavy components
function my_plugin_output() {
    ?>
    <!-- Critical content - inlined in <head> -->
    <style>
        .my-plugin-critical { /* critical styles */ }
    </style>
    
    <!-- Defer heavy content -->
    <div id="my-plugin-content"></div>
    
    <script>
        // Deferred loading after LCP
        window.addEventListener('load', function() {
            fetch('/wp-admin/admin-ajax.php?action=load_plugin_heavy')
                .then(r => r.json())
                .then(data => {
                    document.getElementById('my-plugin-content').innerHTML = data.html;
                    // Load CSS/JS after LCP is measured
                    loadPluginStyles();
                    loadPluginScripts();
                });
        });
    </script>
    <?php
}

First Input Delay (FID): Time from user input to browser response. Target: < 100ms

// Measure FID impact
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('FID:', entry.processingDuration);
    
    // If > 100ms, your plugin may be blocking main thread
    if (entry.processingDuration > 100) {
      console.warn('Plugin may be blocking main thread');
    }
  }
});

observer.observe({entryTypes: ['first-input']});

Minimize FID by offloading heavy computation:

// Before: Blocks main thread for 300ms
document.addEventListener('click', function(e) {
  if (e.target.matches('.my-plugin-button')) {
    // Heavy computation blocks interaction
    const result = expensiveCalculation();
    updateUI(result);
  }
});

// After: Uses Web Workers to avoid blocking
if (window.Worker) {
  const worker = new Worker('/wp-content/plugins/my-plugin/worker.js');
  
  document.addEventListener('click', function(e) {
    if (e.target.matches('.my-plugin-button')) {
      // Computation happens off main thread
      worker.postMessage({data: getData()});
      worker.onmessage = function(e) {
        updateUI(e.data.result);
      };
    }
  });
}

Cumulative Layout Shift (CLS): Visual stability during page load. Target: < 0.1

// Measure CLS caused by your plugin
let clsValue = 0;
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (!entry.hadRecentInput) {
      clsValue += entry.value;
      console.log('CLS:', clsValue);
    }
  }
});

observer.observe({entryTypes: ['layout-shift']});

Prevent layout shifts in plugin UI:

/* Bad: No defined height causes shift when content loads */
.my-plugin-container {
  background: white;
}

/* Good: Reserve space to prevent layout shift */
.my-plugin-container {
  background: white;
  min-height: 300px; /* Reserve space */
}

/* Or use aspect-ratio */
.my-plugin-image {
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

Webpack and Build Tool Budgets

Modern plugin development uses build tools like webpack. Configure these tools to enforce performance budgets automatically.

Webpack Performance Budgets:

// webpack.config.js
module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].js',
    path: __dirname + '/dist'
  },
  
  // Enforce performance budgets
  performance: {
    hints: process.env.NODE_ENV === 'production' ? 'error' : 'warning',
    maxAssetSize: 100 * 1024,      // 100 KB
    maxEntrypointSize: 100 * 1024  // 100 KB
  },
  
  // Code splitting to stay within budgets
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        // Vendor libraries in separate chunk
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10,
          enforce: true
        },
        // Common code in separate chunk
        common: {
          minChunks: 2,
          priority: 5,
          reuseExistingChunk: true,
          name: 'common'
        }
      }
    }
  }
};

Rollup Performance Budgets:

// rollup.config.js
import { terser } from 'rollup-plugin-terser';
import filesize from 'rollup-plugin-filesize';

export default {
  input: 'src/index.js',
  output: {
    file: 'dist/plugin.min.js',
    format: 'umd'
  },
  plugins: [
    // Minify
    terser(),
    
    // Report and enforce bundle size
    filesize({
      showBrotliSize: true,
      // Enforce budget
      onComplete: (sizes) => {
        const MAX_SIZE = 100 * 1024; // 100 KB
        if (sizes.gzip > MAX_SIZE) {
          throw new Error(`Bundle size ${sizes.gzip} exceeds budget ${MAX_SIZE}`);
        }
      }
    })
  ]
};

Esbuild Performance Budgets:

// build.js using esbuild
import * as esbuild from 'esbuild';
import fs from 'fs';

esbuild.build({
  entryPoints: ['src/index.js'],
  outfile: 'dist/plugin.min.js',
  minify: true,
  format: 'umd'
}).then(result => {
  // Check output size
  const stats = fs.statSync('dist/plugin.min.js');
  const sizeKB = stats.size / 1024;
  const budget = 100; // KB
  
  console.log(`Bundle size: ${sizeKB.toFixed(2)} KB`);
  
  if (sizeKB > budget) {
    throw new Error(`Bundle exceeds budget: ${sizeKB.toFixed(2)}KB > ${budget}KB`);
  }
});

Lighthouse CI Integration

Lighthouse CI automates performance testing in your CI/CD pipeline, catching regressions before deployment. Automated performance testing prevents slow features from reaching production by running Lighthouse on every code change and alerting developers to regressions. Without automation, performance gradually degrades as features accumulate. Lighthouse CI integrates seamlessly with GitHub Actions, GitLab CI, and other platforms, making it easy to add performance gates to your CI/CD workflow. Configure it to fail builds if performance scores drop below thresholds or specific metrics exceed limits. This creates team accountability for performance: developers can't accidentally merge slow code without explicitly overriding the checks. The investment in setting up Lighthouse CI pays dividends across the plugin's lifetime by preventing performance regressions from accumulating. Many plugins that started fast become bloated over time not because of intentional decisions but because no one monitored performance as features were added. Lighthouse CI solves this problem automatically.

Setup Lighthouse CI:

# Install Lighthouse CI
npm install -g @lhci/cli@latest

# Configure project
lhci wizard --help

# Example config: lighthouserc.json
{
  "ci": {
    "collect": {
      "url": ["http://localhost:3000/"],
      "numberOfRuns": 3,
      "settings": {
        "configPath": "./lighthouse-config.js"
      }
    },
    "upload": {
      "target": "temporary-public-storage"
    },
    "assert": {
      "preset": "lighthouse:recommended",
      "assertions": {
        "categories:performance": ["error", {"minScore": 0.9}],
        "categories:accessibility": ["error", {"minScore": 0.9}],
        "categories:best-practices": ["error", {"minScore": 0.9}],
        "first-contentful-paint": ["error", {"maxNumericValue": 2000}],
        "largest-contentful-paint": ["error", {"maxNumericValue": 2500}],
        "cumulative-layout-shift": ["error", {"maxNumericValue": 0.1}],
        "first-input-delay": ["error", {"maxNumericValue": 100}]
      }
    }
  }
}

GitHub Actions Integration:

name: Lighthouse CI
on: [push, pull_request]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      
      - name: Install dependencies
        run: npm install
      
      - name: Build plugin
        run: npm run build
      
      - name: Start test server
        run: npm run serve &
        env:
          PORT: 3000
      
      - name: Wait for server
        run: sleep 5
      
      - name: Run Lighthouse CI
        uses: treosh/lighthouse-ci-action@v8
        with:
          configPath: ./lighthouserc.json
          uploadArtifacts: true
          temporaryPublicStorage: true

Performance Assertions:

// lighthouse-config.js - Custom Lighthouse config
module.exports = {
  extends: 'lighthouse:default',
  settings: {
    // Emulate slower connection
    throttling: {
      rttMs: 150,
      downstreamThroughputKbps: 1.6 * 1024,
      upstreamThroughputKbps: 750,
      cpuSlowdownMultiplier: 4
    },
    onlyCategories: ['performance'],
    skipAudits: ['uses-webp-images'] // Skip audits that don't apply
  }
};

Detecting Performance Regressions

Regression detection alerts you when performance gets worse, not just when it exceeds budgets.

Automated regression detection with relative comparisons:

// Compare current build against previous baseline
const currentMetrics = {
  javascript: 102,    // KB
  css: 34,           // KB
  lcp: 2400,         // ms
  cls: 0.08,
  fid: 95            // ms
};

const baseline = {
  javascript: 98,
  css: 32,
  lcp: 2200,
  cls: 0.07,
  fid: 85
};

const tolerance = 0.05; // 5% tolerance

Object.keys(baseline).forEach(metric => {
  const increase = (currentMetrics[metric] - baseline[metric]) / baseline[metric];
  
  if (increase > tolerance) {
    console.error(`Regression in ${metric}: +${(increase * 100).toFixed(1)}%`);
  } else if (increase < -tolerance) {
    console.log(`Improvement in ${metric}: ${(increase * 100).toFixed(1)}%`);
  }
});

Continuous measurement and trend tracking:

#!/bin/bash
# measure-performance.sh - Run before and after changes

# Measure current performance
CURRENT=$(npm run analyze 2>&1 | grep "Size:" | grep -oP '\d+')

# Compare to baseline
BASELINE=$(cat .performance-baseline)
REGRESSION=$((CURRENT - BASELINE))

if [ $REGRESSION -gt 5 ]; then
  echo "⚠️ Performance regression detected: +${REGRESSION}KB"
  exit 1
else
  echo "✓ Performance check passed"
  exit 0
fi

# Update baseline
echo $CURRENT > .performance-baseline

Historical tracking dashboard:

// performance-tracker.js - Track metrics over time
const metrics = {
  timestamp: new Date().toISOString(),
  commit: process.env.GIT_COMMIT,
  javascript: getBundleSize('dist/plugin.min.js'),
  css: getBundleSize('dist/plugin.min.css'),
  lcp: getLighthouseLCP(),
  cls: getLighthouseCLS(),
  requests: countRequests()
};

// Store in CSV for historical comparison
appendMetricsToCSV(metrics);

// Generate trend report
generateTrendReport();

Optimization Techniques

Once you've established budgets and are tracking metrics, optimization becomes targeted and measurable.

Code splitting for admin vs frontend:

// webpack.config.js with code splitting
module.exports = {
  entry: {
    'admin-bundle': './src/admin.js',
    'frontend-bundle': './src/frontend.js'
  },
  output: {
    filename: '[name].[contenthash].js',
    path: __dirname + '/dist'
  }
};

// PHP: Load only necessary bundle
if (is_admin()) {
  wp_enqueue_script('plugin-admin', '/dist/admin-bundle.js');
} else {
  wp_enqueue_script('plugin-frontend', '/dist/frontend-bundle.js');
}

Lazy loading heavy components:

// Only load complex component when needed
function my_plugin_enqueue_scripts() {
    // Always load lightweight init script
    wp_enqueue_script('plugin-init', '/dist/init.js', [], '1.0', true);
    
    // Lazy load admin interface only on plugin pages
    if (isset($_GET['page']) && strpos($_GET['page'], 'my-plugin') === 0) {
        wp_enqueue_script('plugin-admin-ui', '/dist/admin-ui.js', [], '1.0', true);
    }
}

Optimize images in plugin:

// Use images with correct sizes
function my_plugin_get_image($image_id, $size = 'thumbnail') {
    $image = wp_get_attachment_image_src($image_id, $size);
    
    // Output responsive image
    return sprintf(
        '<img src="%s" alt="%s" loading="lazy">',
        esc_url($image[0]),
        get_post_meta($image_id, '_wp_attachment_image_alt', true)
    );
}

WP HealthKit automatically analyzes your plugins' performance impact and compares against industry standards, helping you achieve and maintain performance budgets.


Additional Resources

Broader Context and Best Practices

Performance optimization in WordPress plugins requires understanding the full request lifecycle, from the initial HTTP request through PHP execution, database queries, and response generation. Every millisecond added to this cycle multiplies across every page load for every visitor. A plugin that adds just 50 milliseconds of overhead might seem insignificant, but on a site serving 100,000 page views per day, that translates to nearly 1,400 hours of cumulative user waiting time per year. This perspective helps prioritize optimization efforts where they have the greatest impact on real user experience.

Database queries are the most common performance bottleneck in WordPress plugins, but not all query optimization strategies are equally effective. Adding an index speeds up read operations but slows down writes. Caching eliminates queries entirely but introduces cache invalidation complexity. Denormalization reduces JOIN operations but creates data consistency challenges. Understanding these trade-offs is essential for making informed optimization decisions rather than blindly applying generic advice. Profiling tools and query monitoring help identify which specific queries deserve optimization attention and which optimization strategy best fits each situation.

Core Web Vitals have fundamentally changed how performance is measured and valued. Google's inclusion of LCP, FID, and CLS as ranking factors means that plugin performance now directly impacts site owners' search visibility and revenue. Plugin developers who ignore performance are not just creating a poor user experience. They are actively harming their users' business outcomes. This responsibility drives the growing demand for performance-conscious plugin development and automated performance testing as part of the plugin development workflow.

The relationship between performance and security is often overlooked but critically important. Performance bottlenecks can become denial-of-service vectors when attackers identify expensive operations they can trigger repeatedly. A poorly optimized database query that takes two seconds under normal load might be weaponized to consume all available database connections. Similarly, memory-intensive operations without proper limits can be exploited to crash PHP worker processes. Performance optimization and security hardening are complementary disciplines that reinforce each other when approached holistically.

Broader Context and Best Practices

Performance optimization in WordPress plugins requires understanding the full request lifecycle, from the initial HTTP request through PHP execution, database queries, and response generation. Every millisecond added to this cycle multiplies across every page load for every visitor. A plugin that adds just 50 milliseconds of overhead might seem insignificant, but on a site serving 100,000 page views per day, that translates to nearly 1,400 hours of cumulative user waiting time per year. This perspective helps prioritize optimization efforts where they have the greatest impact on real user experience.

Database queries are the most common performance bottleneck in WordPress plugins, but not all query optimization strategies are equally effective. Adding an index speeds up read operations but slows down writes. Caching eliminates queries entirely but introduces cache invalidation complexity. Denormalization reduces JOIN operations but creates data consistency challenges. Understanding these trade-offs is essential for making informed optimization decisions rather than blindly applying generic advice. Profiling tools and query monitoring help identify which specific queries deserve optimization attention and which optimization strategy best fits each situation.

Core Web Vitals have fundamentally changed how performance is measured and valued. Google's inclusion of LCP, FID, and CLS as ranking factors means that plugin performance now directly impacts site owners' search visibility and revenue. Plugin developers who ignore performance are not just creating a poor user experience. They are actively harming their users' business outcomes. This responsibility drives the growing demand for performance-conscious plugin development and automated performance testing as part of the plugin development workflow.

The relationship between performance and security is often overlooked but critically important. Performance bottlenecks can become denial-of-service vectors when attackers identify expensive operations they can trigger repeatedly. A poorly optimized database query that takes two seconds under normal load might be weaponized to consume all available database connections. Similarly, memory-intensive operations without proper limits can be exploited to crash PHP worker processes. Performance optimization and security hardening are complementary disciplines that reinforce each other when approached holistically.

Frequently Asked Questions

What's a reasonable performance budget for a WordPress plugin?

Depends on functionality. Simple utility plugins: <50KB JS/CSS. Moderate plugins: 50-150KB. Complex plugins: 150-300KB. Admin-only plugins can be larger since admin pages load less frequently. Always question whether features worth the performance cost.

How do I measure Core Web Vitals for my plugin?

Use Google's web-vitals library in your plugin:

import {getCLS, getFID, getLCP} from 'web-vitals';

getCLS(console.log);  // Logs CLS
getFID(console.log);  // Logs FID  
getLCP(console.log);  // Logs LCP

Or test at pagespeed.web.dev or using Lighthouse.

Should I include performance budgets in my development workflow?

Yes, absolutely. Webpack/build tool budgets catch regressions during development. CI/CD budgets catch them before deployment. Regular performance audits catch them in production.

How much performance impact is acceptable?

Google research shows 100ms delay = 1% reduction in conversions. For WordPress sites, plugins should aim for <100ms total impact. Measure and be honest about impact.

Can I use performance budgets as a selling point?

Yes. "Performance-optimized plugin with <50KB footprint" is an attractive differentiator. Publish your performance metrics and budgets. Users appreciate plugins that respect their site speed.

What if my plugin needs to exceed my budget for a feature?

Reconsider: Can the feature be implemented more efficiently? Can it be optional? Can it be loaded on demand? Only exceed budget if feature value justifies performance cost. Document the tradeoff.


WP HealthKit automates this entire process across its 62 verification layers, catching issues that manual review would miss. Whether you're a solo developer or managing an agency portfolio, automated scanning saves hours of manual review time.

Conclusion

WordPress plugin performance budgets transform performance from an afterthought into a first-class concern. By establishing clear targets, measuring continuously, and detecting regressions early, you ensure plugins remain performant as they evolve. Combined with Core Web Vitals monitoring and automated testing, performance budgets create accountability and prevent the death by a thousand cuts that degrades many WordPress sites.

Upload your plugin to WP HealthKit to measure its performance impact alongside security analysis. Our comprehensive scanning identifies performance regression patterns and provides specific optimization recommendations, helping you maintain performance budgets while adding features. Performance-optimized plugins create better user experiences and improve site SEO, making this effort directly valuable to your users.

For more on optimization, explore asset optimization guidance and performance profiling with XDebug.

Ready to audit your plugin?

WP HealthKit checks for all the issues in this article and 40+ more across 62 verification layers.

Comments