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

Wordpress Core Laravel Package

wp-hooks/wordpress-core

Adds WordPress core action and filter hooks as PHP stubs, giving your IDE autocompletion and static analysis tools like PHPStan and Psalm accurate type information for add_action and add_filter calls.

Deep Wiki
Context7

Getting Started

wp-hooks/wordpress-core is not a runtime library — it is a data package. It ships JSON files describing every action and filter registered by WordPress core (name, source file, type, and the parsed docblock). There is no service provider, no autoloaded classes, and nothing to configure. You install it, read the files, and build your own index on top.

composer require --dev wp-hooks/wordpress-core

The payload lives under the package root:

vendor/wp-hooks/wordpress-core/hooks/actions.json
vendor/wp-hooks/wordpress-core/hooks/filters.json

First use case: stop guessing. Load filters.json, key it by name, and you have an instant lookup for "does this hook exist, where is it fired, and what does the docblock say?" — which is enough to power an Artisan command, a validation rule, or a docs page.

use Illuminate\Support\Facades\File;

$filters = collect(File::json(base_path('vendor/wp-hooks/wordpress-core/hooks/filters.json')))
    ->keyBy('name');

$filters->get('the_content');   // name, file, type, core, docs...

Start by dumping one entry (dd($filters->first())) and treat the shape you see as the contract — the schema is generated, not hand-curated.

Implementation Patterns

Wrap it in a registry, don't sprinkle File::json around. One class, one parse, both hook types:

final class HookRegistry
{
    private ?Collection $hooks = null;

    public function all(): Collection
    {
        return $this->hooks ??= collect(['actions', 'filters'])
            ->flatMap(fn (string $type) => File::json(
                base_path("vendor/wp-hooks/wordpress-core/hooks/{$type}.json")
            ))
            ->groupBy('name');
    }

    public function find(string $name): ?array
    {
        return $this->all()->get($name)?->first();
    }

    public function search(string $term): Collection
    {
        return $this->all()->filter(fn (Collection $group, string $name) =>
            str_contains($name, $term)
        );
    }
}

Cache the parsed result, not the file read. For a web-facing hook browser, serialize a trimmed index once (name, type, file, short description) into the cache or into a generated PHP array file that opcache can hold:

Cache::rememberForever('wp-hook-index', fn () => app(HookRegistry::class)
    ->all()
    ->map(fn ($g) => [
        'name'  => $g->first()['name'],
        'type'  => $g->first()['type'],
        'file'  => $g->first()['file'],
        'about' => $g->first()['docs']['short_description'] ?? '',
    ])
    ->values()
    ->all());

Validate hook names in configuration. If your app ships a config file of hooks to listen to, bridge to WP, or forward elsewhere, back it with a validation rule so a typo fails in CI rather than silently doing nothing:

public function validate(string $attribute, mixed $value, Closure $fail): void
{
    if (! app(HookRegistry::class)->find($value)) {
        $fail("Unknown WordPress core hook [{$value}].");
    }
}

Group by source file for a "what runs here" view. The file field is the path in WordPress core that fires the hook. ->groupBy('file') gives you a debugging aid: point it at a core file and list everything it emits.

Use it as a generator input. The most valuable pattern is doc scaffolding: iterate hooks in a namespace-ish family (woocommerce_*, rest_*, save_post_*) and emit stub listener classes or Markdown reference pages from the docs.short_description / docs.long_description fields.

Pair it with wp-hooks/generator when core data isn't enough. That package parses PHP source and produces the same schema for your own plugins/themes; merge its output into the same registry and you get one query surface for core + project hooks.

Gotchas and Tips

  • --no-dev will delete it. This is nearly always installed as a dev dependency, so any feature built on it (docs page, validation rule) breaks in a production build. Either move it to require, or compile the index at deploy time and commit/cache the artifact.
  • No autoloader, no classes. Do not expect WpHooks\... namespaces. Resolve paths via base_path('vendor/...') or, better, Composer\InstalledVersions::getInstallPath('wp-hooks/wordpress-core') so it survives vendor-dir changes.
  • Names are not unique keys. The same hook can be documented at multiple fire sites, so keyBy('name') silently drops entries. Use groupBy if you care about every location.
  • Dynamic hook names appear literally. You'll find entries with interpolation like {$taxonomy}_add_form_fields or "{$new_status}_{$post->post_type}". Exact-match validation will reject legitimate dynamic hooks — special-case a str_contains($name, '{') branch and match on the static prefix/suffix.
  • Matching is case-sensitive, as it is in WordPress. Normalize to lowercase only for search, never for lookup.
  • Docs fields are best-effort. short_description, long_description, tags, and changelog come from parsed docblocks; some hooks have empty or missing docs, and callback signatures live as prose in long_description, not structured args. Don't build a schema that assumes they're populated.
  • Pin to your WordPress version. Package releases track WP releases; a hook added in WP 6.6 won't exist in an older pin, and you'll get false negatives in validation. Bump deliberately alongside your WP target.
  • Size matters. Tens of thousands of entries across two multi-megabyte files. Decoding on every request is a real performance hit — parse once per process (singleton binding) or precompute.
  • File::json() throws on malformed JSON (Laravel 10+). If you point the loader at generated plugin data, wrap it and fail loudly rather than returning an empty collection.
  • Extension point is the data, not the code. There's nothing to subclass. Your seam is the loader: swap the source directory to layer core hooks, project hooks, and third-party hook dumps behind the same HookRegistry API.
  • Licensing: the data is GPL-3.0 (derived from WordPress). Fine for internal tooling and docs; be mindful if you redistribute the JSON inside a proprietary product.
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