You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
WordPress-style post types defined with a fluent API: meta fields (javaabu/meta), media (javaabu/mediapicker), block-editor content, routing, admin and public views in Blade and Inertia React, optional translatable.
Built to the next-gen general rules: CI with test and coverage badges, full docs for people and agents, Laravel Boost guideline and skill, Javaabu codestyle, PHP 8.4 / Laravel 12+ (Laravel packages) or TypeScript (JS packages), Dhivehi and RTL, Blade and Inertia React for views, overridable controllers and policies with javaabu/permissions.
Storage. One posts table for every post type (WordPress-style), with type, title, slug (unique per type), excerpt, content (block-editor JSON), status, published_at, an author morph (any user model, any guard), soft deletes, and nullable translations/lang for translatable. Taxonomy terms live in post_terms (taxonomy, name, slug, description, parent_id, order, translations, lang) with a post_term pivot. Models come from config.
PostTypes::register(
PostType::make('news')
->labels(singular: 'News article', plural: 'News') // translated when shown
->icon('newspaper')
->supports(['content', 'excerpt', 'media', 'meta', 'author'])
->taxonomies(['categories', 'tags'])
->metaFields([TextInput::make('subtitle')->translatable(), Checkbox::make('featured')])
->media([MediaPickerField::make('gallery')->mediaType('image')->multiple()]) // more than the featured image
->blockProfile('default')
->statuses(['draft', 'pending', 'published']) // + Status::make('archived')->public(false)
->permalink('{year}/{month}/{slug}') // under ->slug('news'); configurable in config too
->archive(perPage: 12) // or ->archive(false)
);
PostTypes::taxonomy(Taxonomy::make('categories')->labels('Category', 'Categories')->hierarchical());
Also from config('post-types.types') (array or class names) and PostType subclasses. Scheduling: a published post with a future published_at is "scheduled"; Post::published() / visible() scopes check both, so nothing needs a cron.
Meta, media, content (#4).metaFields() registers MetaFields::for(Post::class, [...], group: $type) and the model's metaGroup() returns the type; the post form nests them with Group::make()->statePath('meta'). media adds a featured_image attachment collection (javaabu/mediapicker MediaPickerField), plus any collections from ->media([...]). content is cast with AsBlockDocument and edited with block-editor's stencil BlockEditorField (profile per type).
Routing and permalinks (#3). Two macros, so apps choose prefix, middleware and guard:
Route::postTypesAdmin(['guard' => 'web_admin', 'prefix' => 'admin', 'name' => 'admin.']) → per type admin/{slug} index (with status tabs and trash), create, store, edit, update, destroy (trash), restore, force delete, bulk; and per taxonomy admin/taxonomies/{taxonomy} terms CRUD. Names admin.news.index, admin.taxonomies.categories.index.
Route::postTypes(['prefix' => '', 'name' => '']) → per type archive (/news), single (from the permalink structure: {slug}, {id}, {year}, {month}, {day}, {category}) and term archives (/news/categories/{term}). Only published, non-future posts; previews of drafts for users who can edit them. $post->url() builds permalinks.
Admin (#5). Index: javaabu/filters (search, status, taxonomy terms, author, date range; sortable title/date) and javaabu/bulk-actions (trash, restore, delete for good, publish, unpublish) with per-type permissions. Create/edit: one stencil form class (title, slug, content, excerpt, featured image, terms, meta group, status, publish date). Blade with javaabu/forms v2 and React (post-types::Posts/Index, Posts/Edit, Terms/Index, Terms/Edit) with @javaabu/forms, Onu and stencil's renderer, shipped through manifest. config('post-types.views'): blade | inertia.
Public views (#6). Archive, single and term archive. Blade templates are looked up WordPress-style (post-types.{type}.single → post-types.single → package default) and are publishable; Inertia pages post-types::Public/Archive, Public/Single, overridable through manifest or per type with ->views([...]). Rendered content uses <x-block-editor::content> / React BlockContent.
RBAC (#11). Per post type, registered through Permissions::register(): view_{type}, edit_{type}, delete_{type}, force_delete_{type}, publish_{type} (+ edit_others_{type}/delete_others_{type} with ->ownable()); per taxonomy view_/edit_/delete_{taxonomy}. PostPolicy / TermPolicy (abilities resolved through the post type), overridable from config, config('permissions.policies') or Gate::policy(). Controllers from config or per route macro; nothing assumes web or App\Models\User (morph author, guard option, tests with two guards).
Translatable (#12). Optional, through Support\Translations. Models\Translatable\Post / Term (JSON storage: title, slug, excerpt, content; term name, slug, description) are chosen when translatable is enabled; meta fields use meta's own translatable support; tested with and without it (CI leg).
Order of work
#1 foundations → #2 definitions, models, migrations → #4 meta/media/content → #3 routing and permalinks → #11 policy and permissions → #5 admin (Blade, then React) → #6 public views → #12 → #9 Dhivehi/RTL → #7 docs, llms.txt, AGENTS.md → #8 Boost. The post type definition API goes on this epic once #2 is pushed.
Decisions / open questions
One table for all types, not a table per type: one model, one set of migrations, menus and search across types; apps that need their own table can point a type at a subclass with ->model().
Hierarchical post types (parent pages with nested permalinks) are out of scope for v1; hierarchical taxonomies are in.
Bulk actions on post types run synchronously. bulk-actions' queued runs rebuild the set with $class::make(), so a set parameterized by post type can't be queued yet. I'll open a non-blocking cross-package issue there.
dynamic-menubuilder: once its contract is posted, posts register one linkable source per post type, feature-detected (suggest, not require).
Contract: post type definition API (on main, for javaabu/cms)
Require it with "javaabu/post-types": "^1.0@dev" and a VCS repository https://github.com/Javaabu/post-types (plus the VCS repositories of its unreleased dependencies, see composer.json). Migrations run on their own (post-types.run_migrations); apps also need spatie/laravel-medialibrary's media table and mediapicker's and meta's migrations.
Defining
useJavaabu\PostTypes\Facades\PostTypes;
useJavaabu\PostTypes\{PostType, Status, Taxonomy};
// A service provider's boot() (or config('post-types.types') / ('post-types.taxonomies'), instances or class names)PostTypes::taxonomy(Taxonomy::make('categories')->labels('Category', 'Categories')->hierarchical());
PostTypes::taxonomy(Taxonomy::make('tags'));
PostTypes::status(Status::make('archived')->label('Archived')->color('info')); // draft, pending, published are built inPostTypes::register(
PostType::make('news')
->labels('News article', 'News') // translated when shown
->icon('newspaper')
->supports(['content', 'excerpt', 'media', 'meta', 'author', 'scheduling']) // ->with(...), ->without(...)
->taxonomies(['categories', 'tags'])
->statuses(['draft', 'pending', 'published', 'archived']) // first is the default; ->defaultStatus()
->metaFields([TextInput::make('subtitle')->translatable(), Checkbox::make('featured')]) // javaabu/meta, group = 'news'
->media([MediaPickerField::make('gallery')->mediaType('image')->multiple()]) // besides featured_image
->blockProfile('default') // javaabu/block-editor profile
->slug('news')->permalink('{year}/{month}/{slug}') // {slug} {id} {year} {month} {day} {<taxonomy>}
->archive(per_page: 12) // ->archive(false), ->public(false)
->ownable() // edit_others_news / delete_others_news
->permission('news') // permission resource, default: key, snake, plural
->model(NewsPost::class) // a Post subclass
->views(['single' => 'news.show'])->pages(['single' => 'News/Show'])
->order(1)
);
Subclasses work too: extend PostType/Taxonomy, set $key and the properties, override setUp(). config('post-types.permalinks.news') overrides base and structure without touching the definition.
Registry (PostTypes facade, PostTypesManager)
types(), find($key), get($key), has(), findBySlug(), registered(fn (PostType $type) => …) (called for every type, now and later), forget(), taxonomies(), getTaxonomy(), typesWithTaxonomy(), statuses(), getStatus(), postModel(), termModel().
Models
Post (posts table, one for every type; type column): postType(), author() (morph, any guard), terms(), termsOf('categories'), syncTerms('categories', [...]), taxonomies attribute (['categories' => [1, 2]], fillable), meta (javaabu/meta, metaGroup() = type), attachments (javaabu/mediapicker, featured_image + ->media() collections), content (AsBlockDocument), url(), permalinkPath(), summary(), featuredImageUrl(), isPublished(), isScheduled(), displayStatus().
Scopes: ofType(), published() (public status, publish date passed), scheduled(), unpublished(), withStatus(), withTerms($taxonomy, $terms), byAuthor($user), latestPublished(), search().
Per type through javaabu/permissions: view_x, edit_x, delete_x, force_delete_x, publish_x (+ edit_others_x, delete_others_x with ownable()); per taxonomy view_/edit_/delete_{taxonomy}. PostPolicy (abilities on PostType and posts: viewAny, create, update, delete, restore, forceDelete, viewTrash, publish) and TermPolicy (on Taxonomy and terms), overridable from config('post-types.policies'), config('permissions.policies') or Gate::policy().
Final summary: javaabu/post-types v1.0 is done on main
Every next-gen issue is closed except #13 (docs.javaabu.com registration, left for you). CI is green on every job (latest run on c616d37):
PHP 8.4/8.5 × Laravel 12/13 × lowest/stable, with coverage from 8.4/13/stable
a leg without Inertia, javaabu/translatable and javaabu/dynamic-menubuilder
Pint, and the guard against javaabu/helpers and settings v1 in production dependencies
the JS job: lint, format, typecheck, Vitest with coverage, and the committed dist check
The suite has 82 PHPUnit tests and 17 Vitest tests.
What was built
Definitions (Fluent post type definitions #2).PostType, Taxonomy and Status, defined fluently, as classes or in config, through the PostTypes registry. Features: content, excerpt, media, meta, author and scheduling. Statuses are draft, pending and published, plus your own. A public status with a future publish date is scheduled, and no cron is needed. The API is in the contract comment above.
Storage. One posts table for every type, plus post_terms and post_term.
Post and Term models with scopes: published, scheduled, unpublished, withTerms, byAuthor, search.
Unique slugs keep Thaana: Str::slug() drops fili, so slugs come from Support\Slug.
Authors are a morph, so any user model and guard works.
The index has status tabs, javaabu/filters (search, status/scheduled, each taxonomy, date, trash, sorts) and javaabu/bulk-actions (publish, move to drafts, trash, restore, delete for good, each checked by the policy).
Create and edit use the stencil PostForm. Without publish_x, users can only save drafts or pending posts.
Taxonomies get term pages with a tree view and parents that can't loop.
Every route also answers JSON.
Public (Public views #6). An archive, term archives (hierarchical archives include child terms) and single posts. Drafts and scheduled posts can be previewed by users who can edit them. Templates are found WordPress-style: ->views(), then post-types.{type}.{page}, then post-types.{page}, then the package default.
Each post type gets view_/edit_/delete_/force_delete_/publish_{type}, and edit_others/delete_others with ->ownable().
Each taxonomy gets view_/edit_/delete_{taxonomy}.
PostPolicy and TermPolicy can be overridden from config, permissions.policies or Gate::policy().
Controllers, forms, filters and bulk actions can all be extended.
Tested with two guards.
Translatable (Optional javaabu/translatable support #12). Optional. Translatable Post (title, excerpt, content; translated content is sanitized) and Term (name, description), and per-language meta inputs. Tested with and without the package.
Menus (dynamic-menubuilder). Optional. Each public post type registers as a menu source, with its archive as the index page. Menus only show published posts, and items are removed when a post is deleted for good. Post implements Contracts\MenuLinkable, which aliases the menubuilder contract when it's installed and is an empty interface otherwise.
Dhivehi and RTL (Dhivehi localization and RTL #9).lang/en and lang/dv (LangTest), logical CSS only (RtlTest), Thaana inputs and slugs, and Thaana in the tests.
One table for every post type. A post type can still use a Post subclass through ->model().
Hierarchical post types. Parent pages with nested permalinks aren't in v1. Hierarchical taxonomies are.
Post and term URLs. The post URL is Post::permalink() and a term archive is Term::archiveUrl(), because javaabu/translatable's trait owns url(). mediapicker hit the same clash.
JS tests use stand-ins. The React tests and typecheck use small stand-ins for block-editor's and mediapicker's React modules (tests/js/shims), because those modules need TipTap and Onu media. Apps get the real ones through manifest.
Not checked in a browser. The pages haven't been opened in a real browser, only in PHP and Vitest tests.
For the user
Codecov: uploads answer "Token required". Make CODECOV_TOKEN available to this repo; the badge stays blank until then.
Dhivehi review: check the terms in docs/advanced-usage/dhivehi-and-rtl.md#for-review.
Release: tag v1.0 once its unreleased dependencies are released, then drop the VCS repositories, including the n4ff4h forks of mediapicker, translatable and dynamic-menubuilder.
npm scopes (manifest:check asks Blade apps to install the React/Inertia dependencies of package pages manifest#17): React, @javaabu/forms and @javaabu/onu (and the @inertiajs/react peer) are now declared with npm(..., for: 'pages'). The registered styles import nothing, so post-types adds nothing to the assets scope. php artisan manifest:check in a Blade-only app no longer asks for React packages because of post-types. tests/Feature/AssetsTest.php covers both a Blade-only app and an Inertia app.
Styles on Inertia pages (Inertia: theme CSS isn't loaded; starter menu label stays English in Dhivehi n4ff4h/cms#12):PostCard (with PostMeta and PostTerms), Public/Archive (and so Public/Term) and Public/Single import resources/css/post-types.css, so Vite bundles it with any page that renders them. Blade is unchanged. A Vitest check makes sure every component using a post-types-* class imports the stylesheet. The admin pages have no styles of their own.
For cms: the documented @import "../../vendor/javaabu/post-types/resources/css/post-types.css" in docs/advanced-usage/inertia-react.md#styles is no longer needed and can be dropped whenever convenient. Keeping it does no harm beyond loading the stylesheet twice.
From javaabu/bulk-actions: the request in Javaabu/bulk-actions#13 is done (bulk-actions main, a95e330). Queued runs now rebuild a set with fromContext($run->context), so PostBulkActions can override context() (['post_type' => $this->post_type?->getKey()]) and static fromContext() (static::for(PostTypes::get($context['post_type']))), then drop ->queueAfter(false). The adoption steps, code and test outline are in Javaabu/bulk-actions#13 (comment). Apps need php artisan migrate for the new context column.
Follow-up in e6274d5 (CI green): post bulk actions now queue large selections like other packages'. PostBulkActions stores the post type's key with withContext(['post_type' => …]) and overrides fromContext() to rebuild with PostBulkActions::for(PostTypes::get(…)). The queueAfter(false) workaround is gone (Javaabu/bulk-actions#13, a95e330). PostsControllerTest::it_queues_large_bulk_actions_for_the_post_type checks the stored context and runs the job: only that type's posts change. The docs, common mistakes and CHANGELOG are updated, including a note to run php artisan migrate for bulk-actions' new context column.
Activity
n4ff4h commentedon Nov 5, 2026
Implementation plan
Studied:
../widgets(closest shape: definitions in code, overridable controller, Blade + Inertia pages through manifest, permissions, optional translatable; I'm copying its tooling, CI and test harness), and the contracts of meta (Javaabu/meta#11), block-editor (Javaabu/block-editor#14), mediapicker (n4ff4h/mediapicker#13, docs), filters (Javaabu/filters#12), bulk-actions (Javaabu/bulk-actions#12), permissions (Javaabu/permissions#14), stencil (Javaabu/stencil#14,statePath()from #16), translatable (n4ff4h/translatable#10) and manifest (Javaabu/manifest#13). dynamic-menubuilder'sMenuLinkabledraft is on itsnext-genbranch.Architecture
Storage. One
poststable for every post type (WordPress-style), withtype,title,slug(unique per type),excerpt,content(block-editor JSON),status,published_at, anauthormorph (any user model, any guard), soft deletes, and nullabletranslations/langfor translatable. Taxonomy terms live inpost_terms(taxonomy,name,slug,description,parent_id,order,translations,lang) with apost_termpivot. Models come from config.Definitions (#2).
Also from
config('post-types.types')(array or class names) andPostTypesubclasses. Scheduling: a published post with a futurepublished_atis "scheduled";Post::published()/visible()scopes check both, so nothing needs a cron.Meta, media, content (#4).
metaFields()registersMetaFields::for(Post::class, [...], group: $type)and the model'smetaGroup()returns the type; the post form nests them withGroup::make()->statePath('meta').mediaadds afeatured_imageattachment collection (javaabu/mediapickerMediaPickerField), plus any collections from->media([...]).contentis cast withAsBlockDocumentand edited with block-editor's stencilBlockEditorField(profile per type).Routing and permalinks (#3). Two macros, so apps choose prefix, middleware and guard:
Route::postTypesAdmin(['guard' => 'web_admin', 'prefix' => 'admin', 'name' => 'admin.'])→ per typeadmin/{slug}index (with status tabs and trash), create, store, edit, update, destroy (trash), restore, force delete, bulk; and per taxonomyadmin/taxonomies/{taxonomy}terms CRUD. Namesadmin.news.index,admin.taxonomies.categories.index.Route::postTypes(['prefix' => '', 'name' => ''])→ per type archive (/news), single (from the permalink structure:{slug},{id},{year},{month},{day},{category}) and term archives (/news/categories/{term}). Only published, non-future posts; previews of drafts for users who can edit them.$post->url()builds permalinks.Admin (#5). Index: javaabu/filters (search, status, taxonomy terms, author, date range; sortable title/date) and javaabu/bulk-actions (trash, restore, delete for good, publish, unpublish) with per-type permissions. Create/edit: one stencil form class (title, slug, content, excerpt, featured image, terms, meta group, status, publish date). Blade with javaabu/forms v2 and React (
post-types::Posts/Index,Posts/Edit,Terms/Index,Terms/Edit) with @javaabu/forms, Onu and stencil's renderer, shipped through manifest.config('post-types.views'):blade|inertia.Public views (#6). Archive, single and term archive. Blade templates are looked up WordPress-style (
post-types.{type}.single→post-types.single→ package default) and are publishable; Inertia pagespost-types::Public/Archive,Public/Single, overridable through manifest or per type with->views([...]). Rendered content uses<x-block-editor::content>/ ReactBlockContent.RBAC (#11). Per post type, registered through
Permissions::register():view_{type},edit_{type},delete_{type},force_delete_{type},publish_{type}(+edit_others_{type}/delete_others_{type}with->ownable()); per taxonomyview_/edit_/delete_{taxonomy}.PostPolicy/TermPolicy(abilities resolved through the post type), overridable from config,config('permissions.policies')orGate::policy(). Controllers from config or per route macro; nothing assumesweborApp\Models\User(morph author, guard option, tests with two guards).Translatable (#12). Optional, through
Support\Translations.Models\Translatable\Post/Term(JSON storage: title, slug, excerpt, content; term name, slug, description) are chosen when translatable is enabled; meta fields use meta's own translatable support; tested with and without it (CI leg).Order of work
#1 foundations → #2 definitions, models, migrations → #4 meta/media/content → #3 routing and permalinks → #11 policy and permissions → #5 admin (Blade, then React) → #6 public views → #12 → #9 Dhivehi/RTL → #7 docs,
llms.txt, AGENTS.md → #8 Boost. The post type definition API goes on this epic once #2 is pushed.Decisions / open questions
->model().$class::make(), so a set parameterized by post type can't be queued yet. I'll open a non-blockingcross-packageissue there.n4ff4h commentedon Nov 5, 2026
Contract: post type definition API (on
main, for javaabu/cms)Require it with
"javaabu/post-types": "^1.0@dev"and a VCS repositoryhttps://github.com/Javaabu/post-types(plus the VCS repositories of its unreleased dependencies, seecomposer.json). Migrations run on their own (post-types.run_migrations); apps also need spatie/laravel-medialibrary'smediatable and mediapicker's and meta's migrations.Defining
Subclasses work too: extend
PostType/Taxonomy, set$keyand the properties, overridesetUp().config('post-types.permalinks.news')overridesbaseandstructurewithout touching the definition.Registry (
PostTypesfacade,PostTypesManager)types(),find($key),get($key),has(),findBySlug(),registered(fn (PostType $type) => …)(called for every type, now and later),forget(),taxonomies(),getTaxonomy(),typesWithTaxonomy(),statuses(),getStatus(),postModel(),termModel().Models
Post(poststable, one for every type;typecolumn):postType(),author()(morph, any guard),terms(),termsOf('categories'),syncTerms('categories', [...]),taxonomiesattribute (['categories' => [1, 2]], fillable),meta(javaabu/meta,metaGroup()= type), attachments (javaabu/mediapicker,featured_image+->media()collections),content(AsBlockDocument),url(),permalinkPath(),summary(),featuredImageUrl(),isPublished(),isScheduled(),displayStatus().Scopes:
ofType(),published()(public status, publish date passed),scheduled(),unpublished(),withStatus(),withTerms($taxonomy, $terms),byAuthor($user),latestPublished(),search().Term(post_terms):taxonomy,name,slug,description,parent_id,order;posts(),parent(),children(),url($post_type),path(),Term::tree('categories').Models\Translatable\Post(title, excerpt, content) andModels\Translatable\Term(name, description), JSON storage.Routes
Authorization
Per type through javaabu/permissions:
view_x,edit_x,delete_x,force_delete_x,publish_x(+edit_others_x,delete_others_xwithownable()); per taxonomyview_/edit_/delete_{taxonomy}.PostPolicy(abilities onPostTypeand posts: viewAny, create, update, delete, restore, forceDelete, viewTrash, publish) andTermPolicy(onTaxonomyand terms), overridable fromconfig('post-types.policies'),config('permissions.policies')orGate::policy().Views
config('post-types.views'):blade|inertia. Admin:post-types::admin.posts.index|edit,admin.terms.index|edit/post-types::Posts/Index|Edit,Terms/Index|Edit. Public:post-types.{type}.{archive|term|single}→post-types.{page}→post-types::public.{page}/post-types::Public/Archive|Term|Single. React exports from@javaabu/post-types(pages,PostCard,postFormComponents, types).n4ff4h commentedon Nov 5, 2026
Final summary: javaabu/post-types v1.0 is done on
mainEvery
next-genissue is closed except #13 (docs.javaabu.com registration, left for you). CI is green on every job (latest run on c616d37):distcheckThe suite has 82 PHPUnit tests and 17 Vitest tests.
What was built
PostType,TaxonomyandStatus, defined fluently, as classes or in config, through thePostTypesregistry. Features: content, excerpt, media, meta, author and scheduling. Statuses are draft, pending and published, plus your own. A public status with a future publish date is scheduled, and no cron is needed. The API is in the contract comment above.poststable for every type, pluspost_termsandpost_term.PostandTermmodels with scopes:published,scheduled,unpublished,withTerms,byAuthor,search.Str::slug()drops fili, so slugs come fromSupport\Slug.MetaFields::nested()(meta[subtitle]).featured_imagecollection plus->media([...])mediapicker fields, validated withLibraryMedia.Route::postTypesAdmin()andRoute::postTypes()take guard, prefix, name, middleware, only/except and controllers.{slug},{id},{year},{month},{day}and taxonomy keys, andconfig('post-types.permalinks')can override them.PostForm. Withoutpublish_x, users can only save drafts or pending posts.->views(), thenpost-types.{type}.{page}, thenpost-types.{page}, then the package default.post-types::Posts/*,Terms/*,Public/*) and their parts ship as@javaabu/post-typesthrough manifest.view_/edit_/delete_/force_delete_/publish_{type}, andedit_others/delete_otherswith->ownable().view_/edit_/delete_{taxonomy}.PostPolicyandTermPolicycan be overridden from config,permissions.policiesorGate::policy().Post(title, excerpt, content; translated content is sanitized) andTerm(name, description), and per-language meta inputs. Tested with and without the package.PostimplementsContracts\MenuLinkable, which aliases the menubuilder contract when it's installed and is an empty interface otherwise.lang/enandlang/dv(LangTest), logical CSS only (RtlTest), Thaana inputs and slugs, and Thaana in the tests.llms.txt(DocsTest), AGENTS.md/CLAUDE.md, and the Boost guideline andjavaabu-post-typesskill with an API reference and common mistakes.Decisions and out of scope
Postsubclass through->model().Post::permalink()and a term archive isTerm::archiveUrl(), because javaabu/translatable's trait ownsurl(). mediapicker hit the same clash.make(), which can't know the post type. Queued runs for sets configured at runtime (context on BulkActionRun) bulk-actions#13 asks for run context. It's non-blocking.tests/js/shims), because those modules need TipTap and Onu media. Apps get the real ones through manifest.For the user
CODECOV_TOKENavailable to this repo; the badge stays blank until then.docs/advanced-usage/dhivehi-and-rtl.md#for-review.n4ff4h commentedon Nov 6, 2026
Follow-up in 2b6acde (CI green):
@javaabu/formsand@javaabu/onu(and the@inertiajs/reactpeer) are now declared withnpm(..., for: 'pages'). The registered styles import nothing, so post-types adds nothing to the assets scope.php artisan manifest:checkin a Blade-only app no longer asks for React packages because of post-types.tests/Feature/AssetsTest.phpcovers both a Blade-only app and an Inertia app.PostCard(withPostMetaandPostTerms),Public/Archive(and soPublic/Term) andPublic/Singleimportresources/css/post-types.css, so Vite bundles it with any page that renders them. Blade is unchanged. A Vitest check makes sure every component using apost-types-*class imports the stylesheet. The admin pages have no styles of their own.@import "../../vendor/javaabu/post-types/resources/css/post-types.css"indocs/advanced-usage/inertia-react.md#stylesis no longer needed and can be dropped whenever convenient. Keeping it does no harm beyond loading the stylesheet twice.n4ff4h commentedon Nov 6, 2026
From javaabu/bulk-actions: the request in Javaabu/bulk-actions#13 is done (bulk-actions
main, a95e330). Queued runs now rebuild a set withfromContext($run->context), soPostBulkActionscan overridecontext()(['post_type' => $this->post_type?->getKey()]) andstatic fromContext()(static::for(PostTypes::get($context['post_type']))), then drop->queueAfter(false). The adoption steps, code and test outline are in Javaabu/bulk-actions#13 (comment). Apps needphp artisan migratefor the newcontextcolumn.n4ff4h commentedon Nov 6, 2026
Follow-up in e6274d5 (CI green): post bulk actions now queue large selections like other packages'.
PostBulkActionsstores the post type's key withwithContext(['post_type' => …])and overridesfromContext()to rebuild withPostBulkActions::for(PostTypes::get(…)). ThequeueAfter(false)workaround is gone (Javaabu/bulk-actions#13, a95e330).PostsControllerTest::it_queues_large_bulk_actions_for_the_post_typechecks the stored context and runs the job: only that type's posts change. The docs, common mistakes and CHANGELOG are updated, including a note to runphp artisan migratefor bulk-actions' newcontextcolumn.