AI Product Scout · Blog

How an 11,000-Line Single-File PHP Plugin Stays Maintainable

No composer, no autoloader, no build step. Shop2LLM's single-file architecture is unconventional — but it delivers zero-overhead performance and forces architectural discipline.

July 5, 2026  ·  8 min read

Table of Contents
  1. Why Single File?
  2. Architecture: Hook-Based Modularity
  3. How Hook-Based Modularity Works
  4. The Plugin De-duplication System
  5. Performance: Why Single File Wins
  6. The Trade-offs (Honestly)

WordPress plugin convention says: use a main plugin file that loads includes, classes split into separate files, PSR-4 autoloading via Composer, and a build step for assets. Shop2LLM violates all of these conventions. It is a single PHP file with 11,000+ lines. No autoloader, no Composer, no node_modules, no build step. This is not a gimmick — it is a deliberate architectural choice with specific engineering trade-offs.

Why Single File?

The decision was driven by three constraints: (1) the plugin needed to be installable by non-technical users without SSH or WP-CLI, (2) performance overhead had to be negligible (+5ms TTFB was the target), and (3) the plugin had to coexist with Yoast, Rank Math, and AIOSEO without conflicts. A single file addresses all three: WordPress loads one file, not 40 includes; no autoloader overhead; and hook-based modularity lets features be disabled at the hook level, avoiding class conflicts with other SEO plugins.

Architecture: Hook-Based Modularity

The file is organized into logical sections separated by banner comments. Each section registers its own hooks:

Section Lines Hook Registration Pattern
Constants & Config 1-80 define() + get_option() defaults
SEO Meta Box ~1500 add_meta_box + save_post + AJAX endpoints
Schema Output ~800 wp_head JSON-LD injection
Sitemap Generation ~600 rewrite_rules + template_redirect
Redirect Manager ~700 template_redirect + admin pages
Content Analysis ~1200 AJAX endpoint + REST API
AI Suggestions ~500 AJAX + wp_remote_post + local fallback
WooCommerce Integration ~600 Conditional on class_exists('WooCommerce')
GSC Integration ~400 OAuth + transients + dashboard widget
SEO Audit & Reports ~800 WP-Cron + wp_mail
Plugin De-duplication ~300 register_deactivation_hook for competitors
Admin Pages & Settings API ~1,500 add_menu_page + settings API + tabs
i18n & Language Files ~500 load_plugin_textdomain + __() wrappers
AI Visibility (llms.txt, MCP, Crawlers) ~1,000 rewrite_rules + REST API + Cron
Assets (CSS/JS) & Dashboard Widget ~520 wp_enqueue_scripts + wp_add_dashboard_widget

The 11 core sections above total ~7,480 lines. The remaining ~3,500 lines of the 11,000-line file cover admin UI rendering, settings registration, i18n string wrappers, AI visibility features (llms.txt generation, MCP server, crawler tracking), and asset enqueuing — bringing the total to 11,000+ lines.

How Hook-Based Modularity Works

Instead of classes and interfaces, each feature section follows a pattern: register hooks at file load time, define callback functions inline, and use a feature flag (stored in wp_options) to conditionally register hooks. This means any feature can be disabled by removing its hook registration — no class instantiation, no dependency injection.

The Plugin De-duplication System

The most interesting architectural challenge was de-duplication. When Shop2LLM is installed alongside Yoast or Rank Math, both plugins try to output meta tags, schema, and sitemaps. The solution: Shop2LLM detects competing plugins and automatically disables its own overlapping features.

Detected Plugin Shop2LLM Disables Shop2LLM Keeps
Yoast SEO Meta tags, sitemap, schema output AI suggestions, redirect manager, SEO audit, WooCommerce integration
Rank Math Meta tags, sitemap, schema output AI suggestions, redirect manager, llms.txt, MCP server
AIOSEO Meta tags, sitemap Everything else
SEOPress Meta tags, schema Everything else

This is implemented via is_plugin_active() checks at hook registration time. If Yoast is active, Shop2LLM's wp_head callback for meta tags is never registered. No conflict, no duplicate output, no performance overhead from unused code.

Performance: Why Single File Wins

Metric Typical Multi-File Plugin Shop2LLM Single File
File system calls at load 20-40 (includes/requires) 1 (the plugin file itself)
Autoloader overhead 5-15ms (Composer classmap scan) 0ms
Memory at load 2-4MB (all classes loaded) Under 1MB (functions loaded inline)
Opcode cache hit rate Lower (many small files) Higher (one large file)
TTFB impact 8-15ms 5ms

PHP's opcode cache (OPcache) is more efficient with fewer, larger files. Each require call triggers a file system stat call. 40 includes = 40 stat calls. One file = one stat call. On shared hosting with slow disk I/O, this difference is measurable.

The Trade-offs (Honestly)

Advantage Disadvantage
Zero configuration — no Composer, no build IDE navigation is harder (no class outline)
Lowest possible performance overhead Git diffs are larger (one file, many changes)
Easy for non-developers to install No PSR-4 autoloading for third-party libraries
Forces architectural discipline PHP_CodeSniffer rules need customization
No class conflicts with other plugins Function naming requires prefixing (shop_to_llm_*)

The single-file approach is not for every plugin. A plugin with 50,000+ lines or complex third-party dependencies would be unmaintainable. But for a focused plugin under 15,000 lines that prioritizes performance and zero-configuration installation, it is a legitimate architectural choice — and the benchmarks prove it works.

Forward