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