@spree/docs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/api-reference/platform/authentication.md +38 -0
- package/dist/api-reference/store-api/authentication.md +188 -0
- package/dist/api-reference/store-api/errors.md +277 -0
- package/dist/api-reference/store-api/idempotency.md +129 -0
- package/dist/api-reference/store-api/introduction.md +34 -0
- package/dist/api-reference/store-api/localization.md +279 -0
- package/dist/api-reference/store-api/metadata.md +160 -0
- package/dist/api-reference/store-api/monetary-amounts.md +65 -0
- package/dist/api-reference/store-api/querying.md +399 -0
- package/dist/api-reference/store-api/rate-limitting.md +103 -0
- package/dist/api-reference/store-api/relations.md +185 -0
- package/dist/api-reference/storefront/authentication.md +88 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-android.md +165 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-ios.md +194 -0
- package/dist/api-reference/tutorials/quick-checkout-with-stripe.md +248 -0
- package/dist/api-reference/v2/fetching-multiple-resources.md +26 -0
- package/dist/api-reference/v2/filtering-and-sorting.md +53 -0
- package/dist/api-reference/v2/introduction.md +22 -0
- package/dist/api-reference/v2/pagination.md +37 -0
- package/dist/api-reference/webhooks-events.md +883 -0
- package/dist/developer/admin/admin.md +205 -0
- package/dist/developer/admin/authentication.md +59 -0
- package/dist/developer/admin/components.md +711 -0
- package/dist/developer/admin/custom-css.md +243 -0
- package/dist/developer/admin/custom-javascript.md +116 -0
- package/dist/developer/admin/extending-ui.md +1964 -0
- package/dist/developer/admin/form-builder.md +444 -0
- package/dist/developer/admin/helper-methods.md +531 -0
- package/dist/developer/admin/navigation.md +805 -0
- package/dist/developer/admin/tables.md +491 -0
- package/dist/developer/advanced/adding_spree_to_rails_app.md +106 -0
- package/dist/developer/cli/quickstart.md +137 -0
- package/dist/developer/contributing/creating-an-extension.md +258 -0
- package/dist/developer/contributing/developing-spree.md +339 -0
- package/dist/developer/contributing/quickstart.md +32 -0
- package/dist/developer/contributing/updating-extensions.md +67 -0
- package/dist/developer/core-concepts/addresses.md +265 -0
- package/dist/developer/core-concepts/adjustments.md +107 -0
- package/dist/developer/core-concepts/architecture.md +177 -0
- package/dist/developer/core-concepts/calculators.md +323 -0
- package/dist/developer/core-concepts/customers.md +230 -0
- package/dist/developer/core-concepts/events.md +624 -0
- package/dist/developer/core-concepts/imports-exports.md +698 -0
- package/dist/developer/core-concepts/inventory.md +191 -0
- package/dist/developer/core-concepts/markets.md +250 -0
- package/dist/developer/core-concepts/media.md +167 -0
- package/dist/developer/core-concepts/metafields.md +187 -0
- package/dist/developer/core-concepts/orders.md +328 -0
- package/dist/developer/core-concepts/payments.md +710 -0
- package/dist/developer/core-concepts/pricing.md +163 -0
- package/dist/developer/core-concepts/products.md +360 -0
- package/dist/developer/core-concepts/promotions.md +322 -0
- package/dist/developer/core-concepts/reports.md +206 -0
- package/dist/developer/core-concepts/search-filtering.md +237 -0
- package/dist/developer/core-concepts/shipments.md +212 -0
- package/dist/developer/core-concepts/slugs.md +111 -0
- package/dist/developer/core-concepts/staff-roles.md +123 -0
- package/dist/developer/core-concepts/store-credits-gift-cards.md +317 -0
- package/dist/developer/core-concepts/stores.md +117 -0
- package/dist/developer/core-concepts/taxes.md +135 -0
- package/dist/developer/core-concepts/translations.md +120 -0
- package/dist/developer/core-concepts/users.md +299 -0
- package/dist/developer/core-concepts/webhooks.md +378 -0
- package/dist/developer/create-spree-app/quickstart.md +158 -0
- package/dist/developer/customization/api.md +93 -0
- package/dist/developer/customization/authentication.md +88 -0
- package/dist/developer/customization/checkout.md +204 -0
- package/dist/developer/customization/configuration.md +55 -0
- package/dist/developer/customization/decorators.md +523 -0
- package/dist/developer/customization/dependencies.md +232 -0
- package/dist/developer/customization/emails.md +21 -0
- package/dist/developer/customization/extensions.md +92 -0
- package/dist/developer/customization/metadata.md +236 -0
- package/dist/developer/customization/model-preferences.md +130 -0
- package/dist/developer/customization/permissions.md +265 -0
- package/dist/developer/customization/quickstart.md +229 -0
- package/dist/developer/customization/routes.md +24 -0
- package/dist/developer/customization/v4/admin-panel.md +78 -0
- package/dist/developer/customization/v4/authentication.md +210 -0
- package/dist/developer/customization/v4/checkout.md +212 -0
- package/dist/developer/customization/v4/deface.md +251 -0
- package/dist/developer/customization/v4/images.md +86 -0
- package/dist/developer/customization/v4/storefront.md +450 -0
- package/dist/developer/deployment/assets.md +87 -0
- package/dist/developer/deployment/aws.md +335 -0
- package/dist/developer/deployment/caching.md +27 -0
- package/dist/developer/deployment/cdn.md +39 -0
- package/dist/developer/deployment/database.md +155 -0
- package/dist/developer/deployment/docker.md +128 -0
- package/dist/developer/deployment/emails.md +77 -0
- package/dist/developer/deployment/environment_variables.md +111 -0
- package/dist/developer/deployment/heroku.md +51 -0
- package/dist/developer/deployment/render.md +95 -0
- package/dist/developer/getting-started/quickstart.md +82 -0
- package/dist/developer/how-to/custom-payment-method.md +374 -0
- package/dist/developer/how-to/custom-promotion.md +373 -0
- package/dist/developer/how-to/custom-report.md +387 -0
- package/dist/developer/how-to/custom-search-provider.md +230 -0
- package/dist/developer/multi-store/quickstart.md +71 -0
- package/dist/developer/multi-store/setup.md +38 -0
- package/dist/developer/multi-tenant/configuration.md +41 -0
- package/dist/developer/multi-tenant/core-concepts.md +75 -0
- package/dist/developer/multi-tenant/installation.md +96 -0
- package/dist/developer/multi-tenant/quickstart.md +20 -0
- package/dist/developer/multi-vendor/installation.md +45 -0
- package/dist/developer/multi-vendor/quickstart.md +17 -0
- package/dist/developer/sdk/admin/quickstart.md +22 -0
- package/dist/developer/sdk/authentication.md +89 -0
- package/dist/developer/sdk/configuration.md +225 -0
- package/dist/developer/sdk/quickstart.md +82 -0
- package/dist/developer/sdk/store/account.md +67 -0
- package/dist/developer/sdk/store/cart-checkout.md +140 -0
- package/dist/developer/sdk/store/markets.md +151 -0
- package/dist/developer/sdk/store/payments.md +96 -0
- package/dist/developer/sdk/store/products.md +149 -0
- package/dist/developer/sdk/store/wishlists.md +52 -0
- package/dist/developer/security/pci_compliance.md +15 -0
- package/dist/developer/security/security_policy.md +68 -0
- package/dist/developer/storefront/blocks.md +285 -0
- package/dist/developer/storefront/custom-css.md +260 -0
- package/dist/developer/storefront/custom-javascript.md +166 -0
- package/dist/developer/storefront/helper-methods.md +1288 -0
- package/dist/developer/storefront/links.md +298 -0
- package/dist/developer/storefront/nextjs/architecture.md +150 -0
- package/dist/developer/storefront/nextjs/customization.md +141 -0
- package/dist/developer/storefront/nextjs/deployment.md +180 -0
- package/dist/developer/storefront/nextjs/quickstart.md +92 -0
- package/dist/developer/storefront/nextjs/spree-next-package.md +314 -0
- package/dist/developer/storefront/pages.md +163 -0
- package/dist/developer/storefront/sections.md +569 -0
- package/dist/developer/storefront/storefront.md +56 -0
- package/dist/developer/storefront/themes.md +161 -0
- package/dist/developer/tutorial/admin.md +134 -0
- package/dist/developer/tutorial/extending-models.md +380 -0
- package/dist/developer/tutorial/file-uploads.md +121 -0
- package/dist/developer/tutorial/introduction.md +33 -0
- package/dist/developer/tutorial/model.md +41 -0
- package/dist/developer/tutorial/page-builder.md +487 -0
- package/dist/developer/tutorial/rich-text.md +73 -0
- package/dist/developer/tutorial/seo.md +332 -0
- package/dist/developer/tutorial/storefront.md +352 -0
- package/dist/developer/tutorial/testing.md +558 -0
- package/dist/developer/upgrades/2.0-to-2.1.md +46 -0
- package/dist/developer/upgrades/2.1-to-2.2.md +59 -0
- package/dist/developer/upgrades/2.2-to-2.3.md +44 -0
- package/dist/developer/upgrades/2.3-to-2.4.md +42 -0
- package/dist/developer/upgrades/3.0-to-3.1.md +47 -0
- package/dist/developer/upgrades/3.1-to-3.2.md +34 -0
- package/dist/developer/upgrades/3.2-to-3.3.md +70 -0
- package/dist/developer/upgrades/3.3-to-3.4.md +36 -0
- package/dist/developer/upgrades/3.4-to-3.5.md +44 -0
- package/dist/developer/upgrades/3.5-to-3.6.md +40 -0
- package/dist/developer/upgrades/3.6-to-3.7.md +62 -0
- package/dist/developer/upgrades/3.7-to-4.0.md +152 -0
- package/dist/developer/upgrades/4.0-to-4.1.md +92 -0
- package/dist/developer/upgrades/4.1-to-4.2.md +109 -0
- package/dist/developer/upgrades/4.10-to-5.0.md +129 -0
- package/dist/developer/upgrades/4.2-to-4.3.md +100 -0
- package/dist/developer/upgrades/4.3-to-4.4.md +125 -0
- package/dist/developer/upgrades/4.4-to-4.5.md +94 -0
- package/dist/developer/upgrades/4.5-to-4.6.md +119 -0
- package/dist/developer/upgrades/4.6-to-4.7.md +39 -0
- package/dist/developer/upgrades/4.8-to-4.9.md +24 -0
- package/dist/developer/upgrades/4.9-to-4.10.md +24 -0
- package/dist/developer/upgrades/4.x-to-4.8.md +52 -0
- package/dist/developer/upgrades/5.0-to-5.1.md +28 -0
- package/dist/developer/upgrades/5.1-to-5.2.md +127 -0
- package/dist/developer/upgrades/5.2-to-5.3.md +338 -0
- package/dist/developer/upgrades/5.3-to-5.4.md +248 -0
- package/dist/developer/upgrades/quickstart.md +36 -0
- package/dist/integrations/analytics/google-analytics.md +64 -0
- package/dist/integrations/analytics/google-tag-manager.md +78 -0
- package/dist/integrations/integrations.md +39 -0
- package/dist/integrations/marketing/klaviyo.md +99 -0
- package/dist/integrations/payments/adyen.md +90 -0
- package/dist/integrations/payments/paypal.md +41 -0
- package/dist/integrations/payments/razorpay.md +45 -0
- package/dist/integrations/payments/stripe.md +109 -0
- package/dist/integrations/search/meilisearch.md +236 -0
- package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +57 -0
- package/dist/integrations/sso-mfa-social-login/storefront.md +56 -0
- package/package.json +27 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: File Uploads
|
|
3
|
+
description: Learn how to add file uploads to the Brands feature
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **INFO:** This guide assumes you've completed the [Model](/developer/tutorial/model), [Admin](/developer/tutorial/admin), and [Rich Text](/developer/tutorial/rich-text) tutorials.
|
|
7
|
+
|
|
8
|
+
In this tutorial, we'll add a logo image upload to our Brand model. Spree uses [Rails Active Storage](https://guides.rubyonrails.org/active_storage_overview.html) for handling file attachments, image processing, and storage.
|
|
9
|
+
|
|
10
|
+
## Step 1: Add Attachment to the Model
|
|
11
|
+
|
|
12
|
+
First, let's add a logo attachment to the Brand model:
|
|
13
|
+
|
|
14
|
+
```ruby app/models/spree/brand.rb {3}
|
|
15
|
+
module Spree
|
|
16
|
+
class Brand < Spree::Base
|
|
17
|
+
has_one_attached :logo
|
|
18
|
+
|
|
19
|
+
# ... existing code ...
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Step 2: Permit the Attachment Attribute
|
|
25
|
+
|
|
26
|
+
For the admin form to accept the file upload, we need to permit the `logo` attribute in the controller.
|
|
27
|
+
|
|
28
|
+
Update your brands controller:
|
|
29
|
+
|
|
30
|
+
```ruby app/controllers/spree/admin/brands_controller.rb {10}
|
|
31
|
+
module Spree
|
|
32
|
+
module Admin
|
|
33
|
+
class BrandsController < ResourceController
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def permitted_resource_params
|
|
37
|
+
params.require(:brand).permit(
|
|
38
|
+
:name,
|
|
39
|
+
:description,
|
|
40
|
+
:logo
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Step 3: Add File Upload Field to the Admin Form
|
|
49
|
+
|
|
50
|
+
Now let's add the file upload field to the brand form. Spree provides a `spree_file_field` helper that handles everything including:
|
|
51
|
+
|
|
52
|
+
- Drag and drop upload
|
|
53
|
+
- Image preview
|
|
54
|
+
- Direct upload to storage
|
|
55
|
+
- Optional image cropping
|
|
56
|
+
|
|
57
|
+
Update your brand form partial:
|
|
58
|
+
|
|
59
|
+
```erb app/views/spree/admin/brands/_form.html.erb {11-19}
|
|
60
|
+
<div class="card mb-6">
|
|
61
|
+
<div class="card-header">
|
|
62
|
+
<h5 class="card-title"><%= Spree.t(:general_settings) %></h5>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="card-body">
|
|
65
|
+
<%= f.spree_text_field :name, required: true %>
|
|
66
|
+
<%= f.spree_rich_text_area :description %>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="card mb-6">
|
|
71
|
+
<div class="card-header">
|
|
72
|
+
<h5 class="card-title"><%= Spree.t(:logo) %></h5>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="card-body">
|
|
75
|
+
<%= f.spree_file_field :logo, width: 300, height: 300 %>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Add cropping functionality
|
|
81
|
+
|
|
82
|
+
To enable cropping functionality, add the `crop: true` option to the `spree_file_field` helper.
|
|
83
|
+
|
|
84
|
+
## Step 4: Display the Logo in the Index Table
|
|
85
|
+
|
|
86
|
+
Let's show a thumbnail of the brand logo in the admin index view.
|
|
87
|
+
|
|
88
|
+
Update the table header partial:
|
|
89
|
+
|
|
90
|
+
```erb app/views/spree/admin/brands/_table_header.html.erb {2}
|
|
91
|
+
<tr>
|
|
92
|
+
<th><%= Spree.t(:logo) %></th>
|
|
93
|
+
<th><%= Spree.t(:name) %></th>
|
|
94
|
+
<th></th>
|
|
95
|
+
</tr>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Update the table row partial to display the logo:
|
|
99
|
+
|
|
100
|
+
```erb app/views/spree/admin/brands/_table_row.html.erb {3-12}
|
|
101
|
+
<tr id="<%= spree_dom_id brand %>" class="cursor-pointer" data-controller="row-link">
|
|
102
|
+
<td data-action="click->row-link#openLink" class="w-70">
|
|
103
|
+
<div class="d-flex align-items-center gap-2">
|
|
104
|
+
<% if brand.logo.attached? %>
|
|
105
|
+
<%= spree_image_tag brand.logo, width: 48, height: 48, class: 'rounded' %>
|
|
106
|
+
<% else %>
|
|
107
|
+
<div class="bg-light rounded d-flex align-items-center justify-content-center" style="width: 48px; height: 48px;">
|
|
108
|
+
<%= icon('photo-off', class: 'text-muted') %>
|
|
109
|
+
</div>
|
|
110
|
+
<% end %>
|
|
111
|
+
<span class="font-weight-bold"><%= brand.name %></span>
|
|
112
|
+
</div>
|
|
113
|
+
</td>
|
|
114
|
+
<td data-action="click->row-link#openLink" class="w-20">
|
|
115
|
+
<%= spree_date(brand.created_at) %>
|
|
116
|
+
</td>
|
|
117
|
+
<td class="actions w-10">
|
|
118
|
+
<%= link_to_edit(brand, data: { row_link_target: :link, turbo_frame: '_top' }) if can? :edit, brand %>
|
|
119
|
+
</td>
|
|
120
|
+
</tr>
|
|
121
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tutorial
|
|
3
|
+
sidebarTitle: Introduction
|
|
4
|
+
description: Learn how to build a custom feature from scratch, covering models, Admin dashboard, API and Storefront.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
This tutorial walks you through creating a complete Spree feature from scratch, covering models, Admin dashboard and API.
|
|
8
|
+
You will also learn how to extend core Spree features to connect them with your new feature.
|
|
9
|
+
By the end, you'll understand how to add new manageable features to the Spree platform.
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
To fully implement a new feature, you will typically create the following components:
|
|
14
|
+
|
|
15
|
+
* Database model
|
|
16
|
+
* Admin Dashboard controllers and views
|
|
17
|
+
* Storefront views
|
|
18
|
+
* Automated tests
|
|
19
|
+
|
|
20
|
+
## Tutorial Sections
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
- [1. Model](/developer/tutorial/model) — Create the Brand model with migrations, validations, and associations
|
|
24
|
+
- [2. Admin Dashboard](/developer/tutorial/admin) — Build admin interface for managing brands
|
|
25
|
+
- [3. Rich Text](/developer/tutorial/rich-text) — Add rich text descriptions using Action Text
|
|
26
|
+
- [4. File Uploads](/developer/tutorial/file-uploads) — Add logo images with Active Storage
|
|
27
|
+
- [5. Extending Core Models](/developer/tutorial/extending-models) — Connect Brands to Products using associations
|
|
28
|
+
- [7. Testing](/developer/tutorial/testing) — Write automated tests for your feature
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
## Example: Building a Brands Feature
|
|
32
|
+
|
|
33
|
+
In this guide we will create a complete "Brands" feature that allows admins to manage [Product](/developer/core-concepts/products) brands.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Model
|
|
3
|
+
description: Learn how to create a database model for the Brands feature
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Step 1: Create the Model and Database Migration
|
|
7
|
+
|
|
8
|
+
To create a new model and database migration file, run the following command:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
bin/rails g spree:model Spree::Brand name:string:index
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
This will create a couple of files:
|
|
15
|
+
- `app/models/spree/brand.rb` - the model file
|
|
16
|
+
- `db/migrate/XXXXXXXXXXXXXX_create_spree_brands.rb` - the database migration file
|
|
17
|
+
|
|
18
|
+
Now run the migration:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bin/rails db:migrate
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
This will create the table `spree_brands` with the column `name` in the database. The `name` column is indexed for faster lookups. Also the model file `app/models/spree/brand.rb` is created.
|
|
25
|
+
|
|
26
|
+
## Step 2: Extend the Model file
|
|
27
|
+
|
|
28
|
+
Now that the model file is created, let's add some additional functionality to it, starting with validations:
|
|
29
|
+
|
|
30
|
+
```ruby app/models/spree/brand.rb {3-4}
|
|
31
|
+
module Spree
|
|
32
|
+
class Brand < Spree::Base
|
|
33
|
+
# Validations
|
|
34
|
+
validates :name, presence: true
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This is a standard [Ruby on Rails ActiveRecord model](https://guides.rubyonrails.org/active_record_basics.html). Let's break down each part:
|
|
40
|
+
- Inherits from `Spree::Base` to automatically inherit all Spree functionality. Also the model itself is namespaced under `Spree::` module, so it's available as `Spree::Brand` in the application.
|
|
41
|
+
- `validates :name, presence: true` - using ActiveRecord validations to ensure that the name is present.
|
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Page Builder Integration
|
|
3
|
+
description: Learn how to connect your Brands feature to Page Builder for admin-manageable pages
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
In this tutorial, we'll enhance our brand pages by integrating them with Spree's Page Builder. This allows store administrators to customize page layouts, add sections, and modify designs without touching code.
|
|
7
|
+
|
|
8
|
+
> **INFO:** This guide assumes you've completed the [Storefront](/developer/tutorial/storefront) tutorial and have working brand pages.
|
|
9
|
+
|
|
10
|
+
## What We're Building
|
|
11
|
+
|
|
12
|
+
By the end of this tutorial, you'll have:
|
|
13
|
+
|
|
14
|
+
- A **Brand List** page type manageable via Page Builder
|
|
15
|
+
- A **Brand** page type for individual brand pages
|
|
16
|
+
- Custom sections: `BrandGrid` and `BrandBanner`
|
|
17
|
+
- Full admin customization support
|
|
18
|
+
|
|
19
|
+
## Understanding Page Builder Architecture
|
|
20
|
+
|
|
21
|
+
Page Builder uses three main components:
|
|
22
|
+
|
|
23
|
+
| Component | Purpose |
|
|
24
|
+
|-----------|---------|
|
|
25
|
+
| **Page** | Defines the page type (e.g., Homepage, Product Details, Brand List) |
|
|
26
|
+
| **Section** | Reusable content blocks within a page (e.g., Hero Banner, Product Grid) |
|
|
27
|
+
| **Block** | Smallest units within sections (e.g., Heading, Text, Button) |
|
|
28
|
+
|
|
29
|
+
## Step 1: Create Page Types
|
|
30
|
+
|
|
31
|
+
### Brand List Page
|
|
32
|
+
|
|
33
|
+
Create a page type for the brands listing:
|
|
34
|
+
|
|
35
|
+
```ruby app/models/spree/pages/brand_list.rb
|
|
36
|
+
module Spree
|
|
37
|
+
module Pages
|
|
38
|
+
class BrandList < Spree::Page
|
|
39
|
+
def icon_name
|
|
40
|
+
'building-store'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def customizable?
|
|
44
|
+
true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def page_builder_url
|
|
48
|
+
return unless page_builder_url_exists?(:brands_path)
|
|
49
|
+
|
|
50
|
+
Spree::Core::Engine.routes.url_helpers.brands_path
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def default_sections
|
|
54
|
+
[
|
|
55
|
+
Spree::PageSections::PageTitle.new(
|
|
56
|
+
preferred_heading: Spree.t(:brands)
|
|
57
|
+
),
|
|
58
|
+
Spree::PageSections::BrandGrid.new
|
|
59
|
+
]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Brand Page
|
|
67
|
+
|
|
68
|
+
Create a page type for individual brand pages:
|
|
69
|
+
|
|
70
|
+
```ruby app/models/spree/pages/brand.rb
|
|
71
|
+
module Spree
|
|
72
|
+
module Pages
|
|
73
|
+
class Brand < Spree::Page
|
|
74
|
+
def icon_name
|
|
75
|
+
'tag'
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def customizable?
|
|
79
|
+
true
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def page_builder_url
|
|
83
|
+
return unless page_builder_url_exists?(:brands_path)
|
|
84
|
+
|
|
85
|
+
brand = Spree::Brand.first
|
|
86
|
+
return unless brand
|
|
87
|
+
|
|
88
|
+
Spree::Core::Engine.routes.url_helpers.brand_path(brand)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def default_sections
|
|
92
|
+
[
|
|
93
|
+
Spree::PageSections::BrandBanner.new,
|
|
94
|
+
Spree::PageSections::ProductGrid.new(
|
|
95
|
+
preferred_heading: Spree.t(:products)
|
|
96
|
+
)
|
|
97
|
+
]
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Step 2: Register Pages
|
|
105
|
+
|
|
106
|
+
Add your pages to the Spree configuration:
|
|
107
|
+
|
|
108
|
+
```ruby config/initializers/spree.rb
|
|
109
|
+
Rails.application.config.after_initialize do
|
|
110
|
+
# Register custom pages
|
|
111
|
+
Spree.page_builder.pages += [
|
|
112
|
+
Spree::Pages::BrandList,
|
|
113
|
+
Spree::Pages::Brand
|
|
114
|
+
]
|
|
115
|
+
end
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Step 3: Create Custom Sections
|
|
119
|
+
|
|
120
|
+
### Brand Grid Section
|
|
121
|
+
|
|
122
|
+
This section displays a grid of all brands:
|
|
123
|
+
|
|
124
|
+
```ruby app/models/spree/page_sections/brand_grid.rb
|
|
125
|
+
module Spree
|
|
126
|
+
module PageSections
|
|
127
|
+
class BrandGrid < Spree::PageSection
|
|
128
|
+
TOP_PADDING_DEFAULT = 40
|
|
129
|
+
BOTTOM_PADDING_DEFAULT = 40
|
|
130
|
+
|
|
131
|
+
preference :show_description, :boolean, default: false
|
|
132
|
+
|
|
133
|
+
def icon_name
|
|
134
|
+
'layout-grid'
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Content sections can be added/removed in Page Builder
|
|
138
|
+
def self.role
|
|
139
|
+
'content'
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def brands
|
|
143
|
+
Spree::Brand.order(:name)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Brand Banner Section
|
|
151
|
+
|
|
152
|
+
This section displays the brand header with logo and description:
|
|
153
|
+
|
|
154
|
+
```ruby app/models/spree/page_sections/brand_banner.rb
|
|
155
|
+
module Spree
|
|
156
|
+
module PageSections
|
|
157
|
+
class BrandBanner < Spree::PageSection
|
|
158
|
+
TOP_PADDING_DEFAULT = 60
|
|
159
|
+
BOTTOM_PADDING_DEFAULT = 40
|
|
160
|
+
|
|
161
|
+
preference :show_logo, :boolean, default: true
|
|
162
|
+
preference :show_description, :boolean, default: true
|
|
163
|
+
preference :layout, :string, default: 'horizontal'
|
|
164
|
+
|
|
165
|
+
before_validation :ensure_valid_layout
|
|
166
|
+
|
|
167
|
+
def icon_name
|
|
168
|
+
'id-badge'
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# System sections are part of the core page functionality
|
|
172
|
+
def self.role
|
|
173
|
+
'system'
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def can_be_deleted?
|
|
177
|
+
false
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
private
|
|
181
|
+
|
|
182
|
+
def ensure_valid_layout
|
|
183
|
+
self.preferred_layout = 'horizontal' unless %w[horizontal vertical].include?(preferred_layout)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Step 4: Register Sections
|
|
191
|
+
|
|
192
|
+
Add your sections to the configuration:
|
|
193
|
+
|
|
194
|
+
```ruby config/initializers/spree.rb
|
|
195
|
+
Rails.application.config.after_initialize do
|
|
196
|
+
# Register custom pages
|
|
197
|
+
Spree.page_builder.pages += [
|
|
198
|
+
Spree::Pages::BrandList,
|
|
199
|
+
Spree::Pages::Brand
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
# Register custom sections
|
|
203
|
+
Spree.page_builder.page_sections += [
|
|
204
|
+
Spree::PageSections::BrandGrid,
|
|
205
|
+
Spree::PageSections::BrandBanner
|
|
206
|
+
]
|
|
207
|
+
end
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Step 5: Create Admin Forms
|
|
211
|
+
|
|
212
|
+
Admin section forms use Spree's Admin Form Builder, which provides helper methods like `spree_select` and `spree_check_box` for consistent styling and functionality.
|
|
213
|
+
|
|
214
|
+
### Brand Grid Admin Form
|
|
215
|
+
|
|
216
|
+
```erb app/views/spree/admin/page_sections/forms/_brand_grid.html.erb
|
|
217
|
+
<%= f.spree_check_box :preferred_show_description,
|
|
218
|
+
label: Spree.t(:show_description),
|
|
219
|
+
data: { action: 'auto-submit#submit' } %>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Brand Banner Admin Form
|
|
223
|
+
|
|
224
|
+
```erb app/views/spree/admin/page_sections/forms/_brand_banner.html.erb
|
|
225
|
+
<%= f.spree_check_box :preferred_show_logo,
|
|
226
|
+
label: Spree.t(:show_logo),
|
|
227
|
+
data: { action: 'auto-submit#submit' } %>
|
|
228
|
+
|
|
229
|
+
<%= f.spree_check_box :preferred_show_description,
|
|
230
|
+
label: Spree.t(:show_description),
|
|
231
|
+
data: { action: 'auto-submit#submit' } %>
|
|
232
|
+
|
|
233
|
+
<% content_for(:design_tab) do %>
|
|
234
|
+
<%= f.spree_select :preferred_layout,
|
|
235
|
+
options_for_select([
|
|
236
|
+
[Spree.t(:horizontal), 'horizontal'],
|
|
237
|
+
[Spree.t(:vertical), 'vertical']
|
|
238
|
+
], @page_section.preferred_layout),
|
|
239
|
+
{ label: Spree.t(:layout) },
|
|
240
|
+
{ data: { action: 'auto-submit#submit' } } %>
|
|
241
|
+
<hr />
|
|
242
|
+
<% end %>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Step 6: Create Storefront Views
|
|
246
|
+
|
|
247
|
+
### Brand Grid Section View
|
|
248
|
+
|
|
249
|
+
```erb app/views/themes/default/spree/page_sections/_brand_grid.html.erb
|
|
250
|
+
<% cache_unless page_builder_enabled?, spree_storefront_base_cache_scope.call(section) do %>
|
|
251
|
+
<div style="<%= section_styles(section) %>">
|
|
252
|
+
<div class="page-container">
|
|
253
|
+
<% brands = section.brands %>
|
|
254
|
+
<% if brands.any? %>
|
|
255
|
+
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
|
|
256
|
+
<% brands.each do |brand| %>
|
|
257
|
+
<%= link_to spree.brand_path(brand),
|
|
258
|
+
class: 'block group',
|
|
259
|
+
data: { turbo_frame: '_top' } do %>
|
|
260
|
+
<div class="aspect-square bg-accent rounded-lg overflow-hidden mb-3">
|
|
261
|
+
<% if brand.logo.attached? %>
|
|
262
|
+
<%= spree_image_tag brand.logo,
|
|
263
|
+
width: 300,
|
|
264
|
+
height: 300,
|
|
265
|
+
class: 'w-full h-full object-contain p-6 group-hover:scale-105 transition-transform',
|
|
266
|
+
alt: brand.name %>
|
|
267
|
+
<% else %>
|
|
268
|
+
<div class="w-full h-full flex items-center justify-center">
|
|
269
|
+
<span class="text-4xl font-medium text-neutral-400">
|
|
270
|
+
<%= brand.name.first.upcase %>
|
|
271
|
+
</span>
|
|
272
|
+
</div>
|
|
273
|
+
<% end %>
|
|
274
|
+
</div>
|
|
275
|
+
<h3 class="font-medium group-hover:text-primary transition-colors">
|
|
276
|
+
<%= brand.name %>
|
|
277
|
+
</h3>
|
|
278
|
+
<% if section.preferred_show_description && brand.description.present? %>
|
|
279
|
+
<p class="mt-1 text-sm text-neutral-600 line-clamp-2">
|
|
280
|
+
<%= brand.description.to_plain_text.truncate(100) %>
|
|
281
|
+
</p>
|
|
282
|
+
<% end %>
|
|
283
|
+
<% end %>
|
|
284
|
+
<% end %>
|
|
285
|
+
</div>
|
|
286
|
+
<% else %>
|
|
287
|
+
<p class="text-neutral-600"><%= Spree.t(:no_brands_found) %></p>
|
|
288
|
+
<% end %>
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
291
|
+
<% end %>
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Brand Banner Section View
|
|
295
|
+
|
|
296
|
+
```erb app/views/themes/default/spree/page_sections/_brand_banner.html.erb
|
|
297
|
+
<% cache_unless page_builder_enabled?, spree_storefront_base_cache_scope.call(section) do %>
|
|
298
|
+
<div style="<%= section_styles(section) %>">
|
|
299
|
+
<div class="page-container">
|
|
300
|
+
<% if brand.present? %>
|
|
301
|
+
<div class="<%= section.preferred_layout == 'horizontal' ? 'flex flex-col md:flex-row gap-8 items-start' : 'text-center' %>">
|
|
302
|
+
<% if section.preferred_show_logo && brand.logo.attached? %>
|
|
303
|
+
<div class="<%= section.preferred_layout == 'horizontal' ? 'w-32 h-32 flex-shrink-0' : 'w-40 h-40 mx-auto mb-6' %> bg-accent rounded-lg">
|
|
304
|
+
<%= spree_image_tag brand.logo,
|
|
305
|
+
width: 160,
|
|
306
|
+
height: 160,
|
|
307
|
+
class: 'w-full h-full object-contain p-4',
|
|
308
|
+
alt: brand.name %>
|
|
309
|
+
</div>
|
|
310
|
+
<% end %>
|
|
311
|
+
|
|
312
|
+
<div>
|
|
313
|
+
<h1 class="text-2xl lg:text-3xl font-medium mb-4">
|
|
314
|
+
<%= brand.name %>
|
|
315
|
+
</h1>
|
|
316
|
+
|
|
317
|
+
<% if section.preferred_show_description && brand.description.present? %>
|
|
318
|
+
<div class="prose max-w-none text-neutral-600">
|
|
319
|
+
<%= brand.description %>
|
|
320
|
+
</div>
|
|
321
|
+
<% end %>
|
|
322
|
+
</div>
|
|
323
|
+
</div>
|
|
324
|
+
<% end %>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
<% end %>
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Step 7: Update the Controller
|
|
331
|
+
|
|
332
|
+
Update your controller to use Page Builder pages:
|
|
333
|
+
|
|
334
|
+
```ruby app/controllers/spree/brands_controller.rb
|
|
335
|
+
module Spree
|
|
336
|
+
class BrandsController < StoreController
|
|
337
|
+
before_action :load_brand, only: [:show]
|
|
338
|
+
|
|
339
|
+
def index
|
|
340
|
+
# Load the Page Builder page
|
|
341
|
+
@current_page = current_theme.pages.find_by(type: 'Spree::Pages::BrandList')
|
|
342
|
+
|
|
343
|
+
# Fallback data if sections need it
|
|
344
|
+
@brands = Spree::Brand.order(:name)
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
def show
|
|
348
|
+
# Load the Page Builder page
|
|
349
|
+
@current_page = current_theme.pages.find_by(type: 'Spree::Pages::Brand')
|
|
350
|
+
|
|
351
|
+
# Load products for the ProductGrid section
|
|
352
|
+
@products = @brand.products
|
|
353
|
+
.active(current_currency)
|
|
354
|
+
.includes(storefront_products_includes)
|
|
355
|
+
.page(params[:page])
|
|
356
|
+
.per(12)
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
private
|
|
360
|
+
|
|
361
|
+
def load_brand
|
|
362
|
+
@brand = Spree::Brand.find(params[:id])
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def accurate_title
|
|
366
|
+
if @brand
|
|
367
|
+
@brand.meta_title.presence || @brand.name
|
|
368
|
+
else
|
|
369
|
+
Spree.t(:brands)
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Step 8: Update Views to Use Page Builder
|
|
377
|
+
|
|
378
|
+
### Brand List Index View
|
|
379
|
+
|
|
380
|
+
```erb app/views/themes/default/spree/brands/index.html.erb
|
|
381
|
+
<%= render_page(@current_page, brands: @brands) %>
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Brand Show View
|
|
385
|
+
|
|
386
|
+
```erb app/views/themes/default/spree/brands/show.html.erb
|
|
387
|
+
<%= render_page(@current_page, brand: @brand, products: @products) %>
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
The `render_page` helper automatically renders all sections in the order defined in Page Builder.
|
|
391
|
+
|
|
392
|
+
## Step 9: Passing Variables to Sections
|
|
393
|
+
|
|
394
|
+
Section views receive variables passed to `render_page`. Update your section views to use them:
|
|
395
|
+
|
|
396
|
+
```erb app/views/themes/default/spree/page_sections/_brand_banner.html.erb
|
|
397
|
+
<% # 'brand' variable is passed from the controller via render_page %>
|
|
398
|
+
<% cache_unless page_builder_enabled?, [spree_storefront_base_cache_scope.call(section), brand] do %>
|
|
399
|
+
<div style="<%= section_styles(section) %>">
|
|
400
|
+
<%# ... use 'brand' variable ... %>
|
|
401
|
+
</div>
|
|
402
|
+
<% end %>
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Step 10: Add Translations
|
|
406
|
+
|
|
407
|
+
```yaml config/locales/en.yml
|
|
408
|
+
en:
|
|
409
|
+
spree:
|
|
410
|
+
brands: Brands
|
|
411
|
+
no_brands_found: No brands found.
|
|
412
|
+
products_by_brand: "Products by %{brand}"
|
|
413
|
+
show_description: Show description
|
|
414
|
+
show_logo: Show logo
|
|
415
|
+
layout: Layout
|
|
416
|
+
horizontal: Horizontal
|
|
417
|
+
vertical: Vertical
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Testing Page Builder Integration
|
|
421
|
+
|
|
422
|
+
1. Start your Rails server
|
|
423
|
+
2. Go to **Admin → Storefront → Pages**
|
|
424
|
+
3. You should see "Brand List" and "Brand" pages
|
|
425
|
+
4. Click on a page to customize it in Page Builder
|
|
426
|
+
5. Add, remove, or reorder sections
|
|
427
|
+
6. Customize section settings
|
|
428
|
+
7. Preview changes in real-time
|
|
429
|
+
|
|
430
|
+
## Section Roles Explained
|
|
431
|
+
|
|
432
|
+
| Role | Description | Can Delete? | Example |
|
|
433
|
+
|------|-------------|-------------|---------|
|
|
434
|
+
| `content` | General content sections | Yes | BrandGrid, ImageBanner |
|
|
435
|
+
| `system` | Core page functionality | No | BrandBanner, ProductDetails |
|
|
436
|
+
| `header` | Layout header sections | No | Header, AnnouncementBar |
|
|
437
|
+
| `footer` | Layout footer sections | No | Footer, Newsletter |
|
|
438
|
+
|
|
439
|
+
## Complete File Structure
|
|
440
|
+
|
|
441
|
+
After completing this tutorial, you should have:
|
|
442
|
+
|
|
443
|
+
```
|
|
444
|
+
app/
|
|
445
|
+
├── controllers/spree/
|
|
446
|
+
│ └── brands_controller.rb
|
|
447
|
+
├── models/spree/
|
|
448
|
+
│ ├── pages/
|
|
449
|
+
│ │ ├── brand.rb
|
|
450
|
+
│ │ └── brand_list.rb
|
|
451
|
+
│ └── page_sections/
|
|
452
|
+
│ ├── brand_banner.rb
|
|
453
|
+
│ └── brand_grid.rb
|
|
454
|
+
└── views/
|
|
455
|
+
├── spree/admin/page_sections/forms/
|
|
456
|
+
│ ├── _brand_banner.html.erb
|
|
457
|
+
│ └── _brand_grid.html.erb
|
|
458
|
+
└── themes/default/spree/
|
|
459
|
+
├── brands/
|
|
460
|
+
│ ├── index.html.erb
|
|
461
|
+
│ └── show.html.erb
|
|
462
|
+
└── page_sections/
|
|
463
|
+
├── _brand_banner.html.erb
|
|
464
|
+
└── _brand_grid.html.erb
|
|
465
|
+
|
|
466
|
+
config/
|
|
467
|
+
├── initializers/
|
|
468
|
+
│ └── spree.rb (updated)
|
|
469
|
+
└── locales/
|
|
470
|
+
└── en.yml (updated)
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
## Benefits of Page Builder Integration
|
|
474
|
+
|
|
475
|
+
| Without Page Builder | With Page Builder |
|
|
476
|
+
|---------------------|-------------------|
|
|
477
|
+
| Developers edit views for layout changes | Admins customize layouts in browser |
|
|
478
|
+
| Code deployment required for design changes | Real-time preview and publish |
|
|
479
|
+
| Fixed page structure | Drag-and-drop section ordering |
|
|
480
|
+
| Hardcoded settings | Admin-configurable preferences |
|
|
481
|
+
|
|
482
|
+
## Related Documentation
|
|
483
|
+
|
|
484
|
+
- [Sections](/developer/storefront/sections) - Creating custom sections
|
|
485
|
+
- [Blocks](/developer/storefront/blocks) - Adding blocks to sections
|
|
486
|
+
- [Pages](/developer/storefront/pages) - Page types and routing
|
|
487
|
+
- [Themes](/developer/storefront/themes) - Theme customization
|