rmscms/shop
rmscms/shop is a Laravel package for adding e-commerce to RMS CMS: product catalogs, categories, carts, orders, and checkout. It provides straightforward store management and a lightweight storefront foundation for launching online shops without heavy dependencies.
rmscms/shop is an add-on for RMS CMS, not a standalone storefront. Verify rmscms/* core is installed, migrated, and booting before you add this package — otherwise you will spend an afternoon debugging tables and admin routes that were never going to exist.composer require rmscms/shop, then confirm discovery: php artisan about (or php artisan package:discover) should list the provider. With 2 stars and a recent-but-thin release history, assume the README is not the source of truth.php artisan vendor:publish --provider="Rmscms\Shop\ShopServiceProvider" — try --tag=config, --tag=migrations, --tag=views individually. Run php artisan vendor:publish --list if a tag is rejected.config/shop.php end to end. For a package this size, the config file is the documentation: it tells you which models are swappable, whether routes are registered, and what the cart/session keys are. Then skim the provider's register()/boot() — you need to know whether migrations, routes, and views load conditionally.php artisan migrate, then seed one category and two products (via tinker is fine) so you have real data before writing any UI.Cache::remember keyed on the category table's updated_at), and eager-load relationships explicitly — a naive $category->products in a Blade @foreach is the classic N+1 that turns a 20-product page into 60 queries.App\Shop\CartService with add/update/remove/totals, implement it over the package's cart, and bind it in a provider. When pricing logic changes — and it will — you edit one file.DB::transaction(). Decrement stock with a conditional update (where('stock', '>=', $qty)->decrement(...)) and abort if zero rows were affected, or you will oversell the last unit under concurrent requests.unit_price, product_name, and sku on the order line at purchase time. Joining back to products for historical invoices means a price edit rewrites your accounting history.pending → paid → shipped → cancelled), and dispatch your own domain events from the transition methods. Put emails, stock returns, and admin notifications in listeners — not scattered through the checkout controller.resources/views/vendor/shop/, or wrap the package's views in your own layout. If the package registers a shop:: view namespace, reference shop::product.card from your app so future package updates land cleanly.$timeout and $tries lower than your worker timeout, or you get opaque MaxAttemptsExceeded failures.RefreshDatabase plus your own factories for products/orders, and in unit tests $this->swap(CartService::class, new FakeCart()). Assume there is no Shop::fake() — this package is small enough that container swaps are the supported path.vendor:publish --force silently clobbers your edited views and config. Diff before forcing, and commit the published files so drift shows up in code review rather than production.shop_orders references a CMS users table that migrates later, the foreign key fails. Check php artisan migrate:status, and rename the migration timestamp if you need to reorder.php artisan route:list and confirm the prefix, middleware, and auth guard on cart/checkout routes. A default-open checkout is a launch-day surprise.Login event with an explicit merge (sum quantities, cap at stock) and clear the session key..env change in staging/production: php artisan config:clear && php artisan config:cache. Package config is read at boot only. Use php artisan config:show shop to confirm your values actually landed.float a total. Tax, shipping, and multi-currency are very likely not implemented — plan to own them in your CartService.php artisan view:clear after publishing. Blade caches compiled views; stale cached templates after a publish is a five-minute confusion that looks like "my override isn't working."scoped bindings in your own code, or reset the package's state in an Octane listener.composer.lock. A 2-star package with a fast release cadence can change default behaviour inside a patch bump. Read the diff of config/ and database/migrations/ between releases before upgrading.php artisan about (discovered?) → php artisan config:show shop (env landed?) → php artisan tinker calling the product/order model directly (package broken vs. my integration broken). The tinker step isolates the two faster than any log.vendor/rmscms/shop survives exactly one composer update.How can I help you explore Laravel packages today?