Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Wp View Laravel Package

morningtrain/wp-view

A lightweight Laravel package that brings WordPress-style view handling to your PHP applications, making it easy to render templates, pass data to views, and keep presentation logic clean and reusable.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a Composer library (not a plugin) that wires Laravel's illuminate/view Blade compiler into a WordPress theme, plus a set of custom directives that wrap common WP template functions.

  1. Install into the theme, not the WP root:

    composer require morningtrain/wp-view
    

    If the theme has no composer.json yet, create one with "type": "wordpress-theme" and a PSR-4 autoload for your theme namespace.

  2. Bootstrap it from functions.php, before any template renders:

    require_once __DIR__ . '/vendor/autoload.php';
    
    use MorningTrain\WP\View\View;
    
    View::setup(
        __DIR__ . '/views',          // .blade.php source
        __DIR__ . '/cache/views'     // compiled PHP; must be writable
    );
    

    Create views/ and cache/views/ and chmod the cache dir so PHP can write. Add cache/ to .gitignore.

  3. First use case — replace one template file. Keep the WP template hierarchy file as a thin controller and move markup into Blade:

    // front-page.php
    \MorningTrain\WP\View\View::render('front-page', [
        'hero' => get_field('hero'),
    ]);
    
    {{-- views/front-page.blade.php --}}
    @extends('layouts.app')
    
    @section('content')
        <h1>{{ get_the_title() }}</h1>
        {!! apply_filters('the_content', get_the_content()) !!}
    @endsection
    

Where to look first: the README for exact View::setup/render signatures, src/View.php for the public API (share, composers, paths), and src/Directives/ for the authoritative list of @wp… directives. With 2 stars and 0 dependents, the source is the documentation — read it once and write your own cheat sheet.

Implementation Patterns

Thin WP files, fat Blade views. Treat page.php, single.php, archive.php as routers: resolve data, then View::render(). This keeps WordPress's template hierarchy intact, so plugins that filter template selection still work.

Layouts mirror header.php/footer.php. If you go fully Blade, the layout must still call wp_head()/wp_footer() (usually via the package's @wpHead/@wpFooter directives) so enqueued assets and plugin hooks fire. If you're migrating incrementally, keep get_header()/get_footer() in the WP files and render only the middle section with Blade — mixing is fine.

WP globals as directives, not raw PHP. Typical set: @wpHead, @wpFooter, @wpBodyClass, @wpLanguageAttributes, loop helpers (@loop/@endloop or @while(have_posts()) + the_post()), @wpGetTemplatePart, @wpNavMenu, @shortcode, @doAction, @applyFilters. Confirm names in src/Directives. Prefer @wpNavMenu('primary') over @php wp_nav_menu([...]); @endphp — directives tend to handle escaping and defaults more cleanly.

Custom queries: always reset. If the package exposes a @query/@endquery pair around a WP_Query, use it and make sure wp_reset_postdata() runs. If not, do it explicitly with @php. A leaked global $post after a secondary loop is the #1 source of "why is my page title wrong" bugs.

Share global data with composers.

View::composer('*', function ($view) {
    $view->with('options', function_exists('get_fields') ? get_fields('options') : []);
});

Guard ACF/plugin calls — composers run on every render, including error pages.

Escaping discipline. {{ }} escapes; {!! !!} does not. Post content needs {!! apply_filters('the_content', get_the_content()) !!}; titles, excerpts, and attribute values stay in {{ }}. Never {!! get_the_title() !!}.

Partials replace get_template_part(). @include('partials.card', ['post' => $post]) is clearer and testable, but it bypasses child-theme override semantics — if you ship a parent theme, document that partial overrides happen via the view path, not get_template_part.

Pass WP_Post objects explicitly rather than relying on the global inside partials. It makes views reusable for related-post sections, REST-rendered fragments, and AJAX responses.

Gotchas and Tips

  • Cache directory is the usual failure point. Missing or non-writable cache/views throws on first render. Also block it from the web: deny from all in .htaccess or location ~ /cache/ { deny all; } in nginx. Blade's mtime check recompiles on source change, but containerised/rsync deploys with preserved timestamps can serve stale output — clear the cache as a deploy step.
  • Autoload order. require vendor/autoload.php must precede View::setup, and both must run before any template file. Put them at the top of functions.php, not inside after_setup_theme, unless the package's own hooks require it.
  • @ collisions. Emails, Twitter handles, and @media in inline CSS get parsed as directives. Escape with @@ or wrap the block in @verbatim … @endverbatim.
  • No <?php ?> in Blade. Use @php … @endphp. Raw tags confuse the compiler and break the compiled-file cache key.
  • Echoing directives. @wpHead and friends print directly; wrapping them in {{ }} produces empty output or double-escaping.
  • render() return vs. echo. Check the source — some builds return a string. If yours does, echo View::render(...).
  • Child themes. If View::setup accepts only one path, child-theme view overrides won't work out of the box. Check for a path/namespace registration method; otherwise build a small resolver that picks child-first.
  • Sage/Bedrock conflict. Sage already ships illuminate/view; running both setups leads to two Blade compilers and confusing directive registration. Don't mix.
  • Extension point. Register custom directives once in a theme service class rather than scattering Blade::directive() calls. Keep names namespaced (@themeIcon) to avoid collisions with future package directives.
  • Pin the version. At 2 stars / 0 dependents, API churn is real. Use a caret constraint, read the changelog on every bump, and write a one-page internal directive cheatsheet — future-you will not remember whether it's @wpBodyClass or @bodyClass.
  • Debugging recipe: blank page → check cache dir permissions and WP_DEBUG log; "directive not found" → it isn't in your installed version; stale markup → delete cache/views/* and reload; wrong global data → dump $post at the top of the layout.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core