phpsword/sword-bundle
Symfony bundle that integrates the Sword library for working with Microsoft Word documents in PHP. It provides bundle configuration and service integration so you can create, read, and manipulate DOCX files within Symfony applications using familiar Symfony services.
First, an honest framing: phpsword/sword-bundle is a Symfony bundle, not a Composer package you can composer require into a Laravel app and expect to work. There's no service provider, no facades, no artisan. As a Laravel developer, you'll get the most value treating it as (a) reference architecture for how to cleanly bridge WordPress and a modern PHP framework, or (b) a tool for a standalone Symfony sidecar that runs WP admin/theme code while your Laravel app consumes the result over HTTP (headless WP).
Minimum setup:
composer require phpsword/sword-bundle
config/bundles.php:
return [
Sword\Bundle\SwordBundle::class => ['all' => true],
];
wp-load.php file inside public/ so WordPress is initialized before the container resolves WP-dependent services.config/packages/sword.yaml with your WP paths and any Twig/hook options.DependencyInjection/ folder (for service tags and configuration keys) and Resources/config/ (for the default service definitions). That tells you the actual extension surface more reliably than the README.First use case: register a small service that hooks into init and registers a custom REST route, then hit it from your Laravel app via Http::get(...). This validates the whole stack — WP loaded, container wired, routing works — before you commit to a larger port.
Hooks as services (DI-first WP): instead of add_action('init', 'my_function') sprinkled across functions.php, register a service and tag it for a given hook. The bundle's compiler passes assemble these into real WP callbacks at boot. This mirrors how you'd use Laravel's event/subscriber pattern — the mental model is nearly identical.
Console commands as your "artisan". A huge selling point over vanilla WP. Custom commands for migrations, data imports, cache clears, and one-off jobs run through the Symfony console binary instead of wp eval-file. If you're used to php artisan, budget time to re-learn the argument/option DSL — it's close but not identical.
Twig/Timber-style views. The bundle swaps PHP templates for Twig, often via Timber. Controllers become plain services injected into the theme layer. If your team already writes Blade, the Twig syntax will be familiar enough to move fast; keep a small shim for WP functions (wp_head, the_post, get_permalink) so template authors don't need to know the bridge.
Headless pattern (recommended for Laravel devs): stand up a light Symfony+WP app exposing REST or GraphQL endpoints, then consume them from Laravel with your normal HTTP client, Sanctum-authenticated where appropriate. You get WordPress's editor and plugin ecosystem for content authoring, Laravel for everything else, and a very clean boundary.
Doctrine for custom tables. Rather than $wpdb->prepare scattered around, define entities mapped to plugin-owned wp_* tables. Read-only access to core tables is possible but fragile — prefer a separate schema prefixed to avoid migrations clashing with WP core upgrades.
Compiler passes for plugin integration. If you register a service per WP plugin, use a compiler pass to only load ones whose plugin is active. This keeps cold boot times sane.
config('...') helper, no Artisan. Every use Illuminate\Support\Facades\... in your head needs a Symfony equivalent ($this->getParameter, EventDispatcherInterface, console commands). Don't half-migrate; commit to Symfony idioms inside the WP app.plugins_loaded but before template rendering. Booting too early means add_action registrations silently no-op; too late and controllers can't find taxonomies. If hooks "just don't fire," confirm wp-load.php is being included from the right directory — WP's ABSPATH constant must be correct.exclude-from-classmap and files autoload entries carefully; a duplicate autoloader will cause "class not found" errors that only appear in prod after composer dump-autoload --optimize.bin/console cache:warmup outside WP works, but services that depend on WP functions will error. Use --no-warmup in CI, or mark WP-dependent services lazy.{{ get_the_title() }} won't work. Either add twig/extra-bundle helpers or write thin Twig functions. Budget an afternoon.wp-config.php's production branch — the profiler will leak through REST responses otherwise. Keep WP_DEBUG and APP_DEBUG independent; conflating them causes surprising 500s on the WP side.config/packages/sword.yaml. If you're missing a hook point in the bundle's docs, grep -r "add_action" vendor/phpsword/ will usually reveal the injection seam.corcel/corcel (Eloquent-backed WP models) or treat WP as a headless CMS. sword-bundle will be more friction than value unless you're specifically running a Symfony app that embeds WordPress.How can I help you explore Laravel packages today?