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

Potter Laravel Package

potterywp/potter

Potter bridges Laravel and WordPress, offering a modern, structured workflow for building WordPress themes and plugins with cleaner code, reusable components, and less boilerplate. A handy toolkit for developers who want Laravel-style ergonomics in WordPress projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Potter is a Composer package that lives inside your theme, not in wp-content/plugins. Treat the theme directory as a small Laravel-ish app.

  1. Scaffold a theme directory under wp-content/themes/my-theme/ with the required style.css header, then:
    cd wp-content/themes/my-theme
    composer require potterywp/potter
    
  2. Make functions.php a thin bootstrap — require the Composer autoloader and hand control to Potter:
    require __DIR__ . '/vendor/autoload.php';
    // boot the Potter theme app (exact class/function name per repo README)
    
  3. Where to look first, in this order:
    • functions.php — the boot entry point and where hooks are registered.
    • views/ — your Blade templates; this replaces index.php, single.php, page.php, archive.php, etc.
    • config/ (if present) — app-level settings: view paths, cache paths, container bindings.
    • app/ — your theme classes: models, view composers, service providers, hook registrars.
  4. Discover the CLI surface before writing anything by hand:
    wp potter --help
    wp potter list
    
    The WP-CLI commands scaffold themes/views and manage assets, which is faster and more consistent than hand-creating files.
  5. First use case: move index.php to views/index.blade.php, create views/layouts/app.blade.php with wp_head() / wp_footer() and @yield('content'), then @extends it from index.blade.php. That one conversion proves the template pipeline, the compiled-view cache path, and asset loading all work.

Note the package's last release was April 2015. Pin the version, and verify PHP compatibility before committing — the underlying Illuminate/Blade components are from the PHP 5.x era.

Implementation Patterns

Layouts and partials instead of get_header() / get_template_part().

{{-- views/layouts/app.blade.php --}}
<!doctype html>
<html @php(language_attributes()) @endphp>
<head>@php(wp_head()) @endphp</head>
<body @php(body_class()) @endphp>
  @include('partials.nav')
  @yield('content')
  @php(wp_footer()) @endphp
</body>
</html>

Keep every template dumb: query in PHP, loop in Blade.

Eloquent-style models for queries. The value is replacing raw WP_Query argument arrays with readable chains:

$posts = Post::where('post_type', 'post')
    ->orderBy('date', 'desc')
    ->limit(3)
    ->get();

Pass the result into the view (View::make('home', compact('posts')), a view composer, or whatever the theme's renderer exposes) and @foreach it. Do this in app/ classes or a small controller-ish layer rather than inline in functions.php.

Service container for theme logic. Register bindings once, resolve everywhere:

// app/providers/ThemeServiceProvider.php
$this->app->bind('nav.walker', function () {
    return new App\Support\NavWalker();
});

Then hook callbacks can accept container-resolved dependencies instead of reaching for globals. This is the main day-to-day win over vanilla WP: testable, injectable theme classes.

Hooks stay native. Register actions and filters the WordPress way — Potter doesn't replace them:

add_action('after_setup_theme', [App\Setup::class, 'themeSupports']);
add_filter('excerpt_length', fn() => 24);

Put these in a single app/hooks.php or a provider so the hook surface is greppable.

Facades for WP globals. Use the package's facades (Asset, Post, Theme, etc. — check the repo for the exact list) instead of global $wpdb-style access. In Blade, a facade call is cleaner than a pile of @php blocks.

Assets via the facade/config, not raw wp_enqueue_*. One place declares handles, versions, and paths; the CLI commands then handle copying/compiling. This is the piece that actually saves time on multi-template themes.

Scaffolding workflow. For each new template type: wp potter ... (make view / make model / make provider) → fill in the Blade body → verify in the browser. Consistent structure across a team matters more than any single feature here.

Gotchas and Tips

  • Age and dependency conflicts are the #1 risk. Potter bundles Illuminate components from 2015. If the site also loads a plugin with a modern illuminate/* or a second Composer autoloader, you'll get "cannot redeclare class" or silently wrong Blade versions. Keep the theme's vendor/ isolated and audit composer.lock.
  • Compiled Blade cache. Blade writes compiled PHP to a cache directory (typically under the theme or uploads). If templates don't appear to update, that directory is stale or not writable — clear it via the CLI command or delete it manually. This is the most common "my change did nothing" bug.
  • Blade error line numbers lie. Errors point at the compiled file, not your .blade.php. While debugging, keep compiled files around (disable cache/don't auto-purge) so you can open the compiled output and match it back.
  • Escaping. {{ }} HTML-escapes; {!! !!} does not. Never pipe the_content() through {!! !!} for untrusted authors, and remember the_title() echoes — it doesn't return. Use get_the_title() inside {{ }}.
  • Eloquent is a veneer over WP_Query, not real Eloquent. No lazy relations, no save(), no migrations, no model events. Pagination is especially divergent — a model "paginator" will not automatically cooperate with the_posts_pagination() / paginate_links(). Verify the query's paged handling manually.
  • The loop and globals. Models fetched outside have_posts() won't set up $post. If you call template tags like the_permalink() on a model's post, call setup_postdata() (or the model's equivalent) first; otherwise you get the wrong post's data.
  • Template hierarchy mapping is not 1:1. Confirm what filenames Potter expects for front-page, home, 404, search, and custom post type singles — Blade view names must match its resolver, not WordPress's .php names.
  • Layout omissions. Old-style layouts frequently forget wp_body_open() (required by many modern plugins) and wp_head() ordering. Add them explicitly; Potter won't.
  • Debugging setup. Set WP_DEBUG / WP_DEBUG_LOG and enable Potter's debug flag if it has one (keeps compiled views, surfaces container resolution errors). If a facade returns null, the binding probably wasn't registered before the template rendered — check provider registration order in the bootstrap.
  • Extension points worth knowing: custom Blade directives (Blade::directive('wphead', ...)) for noisy WP calls, view composers for shared data (menus, options) instead of repeating queries in templates, and container bindings for swapping implementations (e.g., a stub nav walker in tests).
  • Budget for maintenance. With no releases since 2015, plan for either a fork you control or a documented exit path. The Blade templates and app classes port reasonably to a modern Laravel-zero/Blade-only setup; the container and facade glue does not.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource