@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.
Files changed (183) hide show
  1. package/README.md +54 -0
  2. package/dist/api-reference/platform/authentication.md +38 -0
  3. package/dist/api-reference/store-api/authentication.md +188 -0
  4. package/dist/api-reference/store-api/errors.md +277 -0
  5. package/dist/api-reference/store-api/idempotency.md +129 -0
  6. package/dist/api-reference/store-api/introduction.md +34 -0
  7. package/dist/api-reference/store-api/localization.md +279 -0
  8. package/dist/api-reference/store-api/metadata.md +160 -0
  9. package/dist/api-reference/store-api/monetary-amounts.md +65 -0
  10. package/dist/api-reference/store-api/querying.md +399 -0
  11. package/dist/api-reference/store-api/rate-limitting.md +103 -0
  12. package/dist/api-reference/store-api/relations.md +185 -0
  13. package/dist/api-reference/storefront/authentication.md +88 -0
  14. package/dist/api-reference/tutorials/adyen-integration-guide-for-android.md +165 -0
  15. package/dist/api-reference/tutorials/adyen-integration-guide-for-ios.md +194 -0
  16. package/dist/api-reference/tutorials/quick-checkout-with-stripe.md +248 -0
  17. package/dist/api-reference/v2/fetching-multiple-resources.md +26 -0
  18. package/dist/api-reference/v2/filtering-and-sorting.md +53 -0
  19. package/dist/api-reference/v2/introduction.md +22 -0
  20. package/dist/api-reference/v2/pagination.md +37 -0
  21. package/dist/api-reference/webhooks-events.md +883 -0
  22. package/dist/developer/admin/admin.md +205 -0
  23. package/dist/developer/admin/authentication.md +59 -0
  24. package/dist/developer/admin/components.md +711 -0
  25. package/dist/developer/admin/custom-css.md +243 -0
  26. package/dist/developer/admin/custom-javascript.md +116 -0
  27. package/dist/developer/admin/extending-ui.md +1964 -0
  28. package/dist/developer/admin/form-builder.md +444 -0
  29. package/dist/developer/admin/helper-methods.md +531 -0
  30. package/dist/developer/admin/navigation.md +805 -0
  31. package/dist/developer/admin/tables.md +491 -0
  32. package/dist/developer/advanced/adding_spree_to_rails_app.md +106 -0
  33. package/dist/developer/cli/quickstart.md +137 -0
  34. package/dist/developer/contributing/creating-an-extension.md +258 -0
  35. package/dist/developer/contributing/developing-spree.md +339 -0
  36. package/dist/developer/contributing/quickstart.md +32 -0
  37. package/dist/developer/contributing/updating-extensions.md +67 -0
  38. package/dist/developer/core-concepts/addresses.md +265 -0
  39. package/dist/developer/core-concepts/adjustments.md +107 -0
  40. package/dist/developer/core-concepts/architecture.md +177 -0
  41. package/dist/developer/core-concepts/calculators.md +323 -0
  42. package/dist/developer/core-concepts/customers.md +230 -0
  43. package/dist/developer/core-concepts/events.md +624 -0
  44. package/dist/developer/core-concepts/imports-exports.md +698 -0
  45. package/dist/developer/core-concepts/inventory.md +191 -0
  46. package/dist/developer/core-concepts/markets.md +250 -0
  47. package/dist/developer/core-concepts/media.md +167 -0
  48. package/dist/developer/core-concepts/metafields.md +187 -0
  49. package/dist/developer/core-concepts/orders.md +328 -0
  50. package/dist/developer/core-concepts/payments.md +710 -0
  51. package/dist/developer/core-concepts/pricing.md +163 -0
  52. package/dist/developer/core-concepts/products.md +360 -0
  53. package/dist/developer/core-concepts/promotions.md +322 -0
  54. package/dist/developer/core-concepts/reports.md +206 -0
  55. package/dist/developer/core-concepts/search-filtering.md +237 -0
  56. package/dist/developer/core-concepts/shipments.md +212 -0
  57. package/dist/developer/core-concepts/slugs.md +111 -0
  58. package/dist/developer/core-concepts/staff-roles.md +123 -0
  59. package/dist/developer/core-concepts/store-credits-gift-cards.md +317 -0
  60. package/dist/developer/core-concepts/stores.md +117 -0
  61. package/dist/developer/core-concepts/taxes.md +135 -0
  62. package/dist/developer/core-concepts/translations.md +120 -0
  63. package/dist/developer/core-concepts/users.md +299 -0
  64. package/dist/developer/core-concepts/webhooks.md +378 -0
  65. package/dist/developer/create-spree-app/quickstart.md +158 -0
  66. package/dist/developer/customization/api.md +93 -0
  67. package/dist/developer/customization/authentication.md +88 -0
  68. package/dist/developer/customization/checkout.md +204 -0
  69. package/dist/developer/customization/configuration.md +55 -0
  70. package/dist/developer/customization/decorators.md +523 -0
  71. package/dist/developer/customization/dependencies.md +232 -0
  72. package/dist/developer/customization/emails.md +21 -0
  73. package/dist/developer/customization/extensions.md +92 -0
  74. package/dist/developer/customization/metadata.md +236 -0
  75. package/dist/developer/customization/model-preferences.md +130 -0
  76. package/dist/developer/customization/permissions.md +265 -0
  77. package/dist/developer/customization/quickstart.md +229 -0
  78. package/dist/developer/customization/routes.md +24 -0
  79. package/dist/developer/customization/v4/admin-panel.md +78 -0
  80. package/dist/developer/customization/v4/authentication.md +210 -0
  81. package/dist/developer/customization/v4/checkout.md +212 -0
  82. package/dist/developer/customization/v4/deface.md +251 -0
  83. package/dist/developer/customization/v4/images.md +86 -0
  84. package/dist/developer/customization/v4/storefront.md +450 -0
  85. package/dist/developer/deployment/assets.md +87 -0
  86. package/dist/developer/deployment/aws.md +335 -0
  87. package/dist/developer/deployment/caching.md +27 -0
  88. package/dist/developer/deployment/cdn.md +39 -0
  89. package/dist/developer/deployment/database.md +155 -0
  90. package/dist/developer/deployment/docker.md +128 -0
  91. package/dist/developer/deployment/emails.md +77 -0
  92. package/dist/developer/deployment/environment_variables.md +111 -0
  93. package/dist/developer/deployment/heroku.md +51 -0
  94. package/dist/developer/deployment/render.md +95 -0
  95. package/dist/developer/getting-started/quickstart.md +82 -0
  96. package/dist/developer/how-to/custom-payment-method.md +374 -0
  97. package/dist/developer/how-to/custom-promotion.md +373 -0
  98. package/dist/developer/how-to/custom-report.md +387 -0
  99. package/dist/developer/how-to/custom-search-provider.md +230 -0
  100. package/dist/developer/multi-store/quickstart.md +71 -0
  101. package/dist/developer/multi-store/setup.md +38 -0
  102. package/dist/developer/multi-tenant/configuration.md +41 -0
  103. package/dist/developer/multi-tenant/core-concepts.md +75 -0
  104. package/dist/developer/multi-tenant/installation.md +96 -0
  105. package/dist/developer/multi-tenant/quickstart.md +20 -0
  106. package/dist/developer/multi-vendor/installation.md +45 -0
  107. package/dist/developer/multi-vendor/quickstart.md +17 -0
  108. package/dist/developer/sdk/admin/quickstart.md +22 -0
  109. package/dist/developer/sdk/authentication.md +89 -0
  110. package/dist/developer/sdk/configuration.md +225 -0
  111. package/dist/developer/sdk/quickstart.md +82 -0
  112. package/dist/developer/sdk/store/account.md +67 -0
  113. package/dist/developer/sdk/store/cart-checkout.md +140 -0
  114. package/dist/developer/sdk/store/markets.md +151 -0
  115. package/dist/developer/sdk/store/payments.md +96 -0
  116. package/dist/developer/sdk/store/products.md +149 -0
  117. package/dist/developer/sdk/store/wishlists.md +52 -0
  118. package/dist/developer/security/pci_compliance.md +15 -0
  119. package/dist/developer/security/security_policy.md +68 -0
  120. package/dist/developer/storefront/blocks.md +285 -0
  121. package/dist/developer/storefront/custom-css.md +260 -0
  122. package/dist/developer/storefront/custom-javascript.md +166 -0
  123. package/dist/developer/storefront/helper-methods.md +1288 -0
  124. package/dist/developer/storefront/links.md +298 -0
  125. package/dist/developer/storefront/nextjs/architecture.md +150 -0
  126. package/dist/developer/storefront/nextjs/customization.md +141 -0
  127. package/dist/developer/storefront/nextjs/deployment.md +180 -0
  128. package/dist/developer/storefront/nextjs/quickstart.md +92 -0
  129. package/dist/developer/storefront/nextjs/spree-next-package.md +314 -0
  130. package/dist/developer/storefront/pages.md +163 -0
  131. package/dist/developer/storefront/sections.md +569 -0
  132. package/dist/developer/storefront/storefront.md +56 -0
  133. package/dist/developer/storefront/themes.md +161 -0
  134. package/dist/developer/tutorial/admin.md +134 -0
  135. package/dist/developer/tutorial/extending-models.md +380 -0
  136. package/dist/developer/tutorial/file-uploads.md +121 -0
  137. package/dist/developer/tutorial/introduction.md +33 -0
  138. package/dist/developer/tutorial/model.md +41 -0
  139. package/dist/developer/tutorial/page-builder.md +487 -0
  140. package/dist/developer/tutorial/rich-text.md +73 -0
  141. package/dist/developer/tutorial/seo.md +332 -0
  142. package/dist/developer/tutorial/storefront.md +352 -0
  143. package/dist/developer/tutorial/testing.md +558 -0
  144. package/dist/developer/upgrades/2.0-to-2.1.md +46 -0
  145. package/dist/developer/upgrades/2.1-to-2.2.md +59 -0
  146. package/dist/developer/upgrades/2.2-to-2.3.md +44 -0
  147. package/dist/developer/upgrades/2.3-to-2.4.md +42 -0
  148. package/dist/developer/upgrades/3.0-to-3.1.md +47 -0
  149. package/dist/developer/upgrades/3.1-to-3.2.md +34 -0
  150. package/dist/developer/upgrades/3.2-to-3.3.md +70 -0
  151. package/dist/developer/upgrades/3.3-to-3.4.md +36 -0
  152. package/dist/developer/upgrades/3.4-to-3.5.md +44 -0
  153. package/dist/developer/upgrades/3.5-to-3.6.md +40 -0
  154. package/dist/developer/upgrades/3.6-to-3.7.md +62 -0
  155. package/dist/developer/upgrades/3.7-to-4.0.md +152 -0
  156. package/dist/developer/upgrades/4.0-to-4.1.md +92 -0
  157. package/dist/developer/upgrades/4.1-to-4.2.md +109 -0
  158. package/dist/developer/upgrades/4.10-to-5.0.md +129 -0
  159. package/dist/developer/upgrades/4.2-to-4.3.md +100 -0
  160. package/dist/developer/upgrades/4.3-to-4.4.md +125 -0
  161. package/dist/developer/upgrades/4.4-to-4.5.md +94 -0
  162. package/dist/developer/upgrades/4.5-to-4.6.md +119 -0
  163. package/dist/developer/upgrades/4.6-to-4.7.md +39 -0
  164. package/dist/developer/upgrades/4.8-to-4.9.md +24 -0
  165. package/dist/developer/upgrades/4.9-to-4.10.md +24 -0
  166. package/dist/developer/upgrades/4.x-to-4.8.md +52 -0
  167. package/dist/developer/upgrades/5.0-to-5.1.md +28 -0
  168. package/dist/developer/upgrades/5.1-to-5.2.md +127 -0
  169. package/dist/developer/upgrades/5.2-to-5.3.md +338 -0
  170. package/dist/developer/upgrades/5.3-to-5.4.md +248 -0
  171. package/dist/developer/upgrades/quickstart.md +36 -0
  172. package/dist/integrations/analytics/google-analytics.md +64 -0
  173. package/dist/integrations/analytics/google-tag-manager.md +78 -0
  174. package/dist/integrations/integrations.md +39 -0
  175. package/dist/integrations/marketing/klaviyo.md +99 -0
  176. package/dist/integrations/payments/adyen.md +90 -0
  177. package/dist/integrations/payments/paypal.md +41 -0
  178. package/dist/integrations/payments/razorpay.md +45 -0
  179. package/dist/integrations/payments/stripe.md +109 -0
  180. package/dist/integrations/search/meilisearch.md +236 -0
  181. package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +57 -0
  182. package/dist/integrations/sso-mfa-social-login/storefront.md +56 -0
  183. package/package.json +27 -0
@@ -0,0 +1,805 @@
1
+ ---
2
+ title: Extending Admin Navigation
3
+ sidebarTitle: Navigation
4
+ ---
5
+
6
+ Spree Admin Dashboard provides a flexible navigation system that allows you to easily extend the sidebar navigation with your own menu items without modifying the core codebase. This enables safe updates while maintaining your customizations.
7
+
8
+ > **INFO:** Starting with Spree 5.2, the navigation system uses a declarative API accessible via `Spree.admin.navigation`. This allows you to programmatically add, modify, and remove navigation items directly in your initializers.
9
+
10
+ ## Basic Usage
11
+
12
+ Add navigation items in your `config/initializers/spree.rb` file:
13
+
14
+ ```ruby config/initializers/spree.rb
15
+ Rails.application.config.after_initialize do
16
+ sidebar_nav = Spree.admin.navigation.sidebar
17
+
18
+ sidebar_nav.add :brands,
19
+ label: :brands,
20
+ url: :admin_brands_path,
21
+ icon: 'award',
22
+ position: 35,
23
+ active: -> { controller_name == 'brands' },
24
+ if: -> { can?(:manage, Spree::Brand) }
25
+ end
26
+ ```
27
+
28
+ ## Available Options
29
+
30
+ All navigation items support the following options:
31
+
32
+ - **`label`** (`Symbol or String`) — The text label for the navigation item. Can be a symbol (translation key using `Spree.t`) or a string.
33
+
34
+ - **`url`** (`Symbol or Lambda`) — The URL for the navigation item. Can be a route helper symbol (`:admin_brands_path`) or a lambda returning a URL.
35
+
36
+ - **`icon`** (`String`) — Icon name from [Tabler Icons](https://tabler.io/icons).
37
+
38
+ - **`position`** (`Integer`) — Numeric position in the menu. Lower numbers appear first.
39
+
40
+ - **`active`** (`Lambda`) — Lambda to determine if the link should be highlighted as active. Receives view context.
41
+
42
+ - **`if`** (`Lambda`) — Conditional display logic. The item only appears if this lambda returns true. Has access to view context helpers like `can?`, `current_store`, etc.
43
+
44
+ - **`badge`** (`String or Lambda`) — Badge text/count to display next to the label. Can be a string or lambda that returns a value.
45
+
46
+ - **`badge_class`** (`String`) — CSS class for badge styling (e.g., `'badge-info'`, `'badge-warning'`).
47
+
48
+ - **`tooltip`** (`String`) — Tooltip text shown on hover.
49
+
50
+ - **`target`** (`String`) — Link target attribute (e.g., `'_blank'` to open in a new tab).
51
+
52
+ - **`section_label`** (`String`) — Creates a section divider with the given label instead of a clickable link.
53
+
54
+ - **`parent`** (`Symbol`) — The key of an existing navigation item to nest this item under. This is the simplest way to add items to existing submenus.
55
+
56
+ ## Navigation Contexts
57
+
58
+ The navigation system supports multiple contexts. Spree provides predefined contexts for common use cases, and you can register custom contexts for your specific needs.
59
+
60
+ ### Sidebar Navigation
61
+
62
+ The main sidebar navigation:
63
+
64
+ ```ruby
65
+ sidebar_nav = Spree.admin.navigation.sidebar
66
+ ```
67
+
68
+ ### Settings Navigation
69
+
70
+ Navigation in the Settings area:
71
+
72
+ ```ruby
73
+ settings_nav = Spree.admin.navigation.settings
74
+ ```
75
+
76
+ ### Page Tab Navigation
77
+
78
+ Spree provides several predefined tab contexts for common admin pages:
79
+
80
+ ```ruby
81
+ tax_tabs = Spree.admin.navigation.tax_tabs
82
+ shipping_tabs = Spree.admin.navigation.shipping_tabs
83
+ team_tabs = Spree.admin.navigation.team_tabs
84
+ stock_tabs = Spree.admin.navigation.stock_tabs
85
+ returns_tabs = Spree.admin.navigation.returns_tabs
86
+ developers_tabs = Spree.admin.navigation.developers_tabs
87
+ audit_tabs = Spree.admin.navigation.audit_tabs
88
+ ```
89
+
90
+ ### Registering Contexts
91
+
92
+ Use `register_context` to create a new navigation context:
93
+
94
+ ```ruby
95
+ # Returns a Spree::Admin::Navigation instance
96
+ custom_tabs = Spree.admin.navigation.register_context(:custom_tabs)
97
+ ```
98
+
99
+ - **`name`** (`Symbol or String`) — The unique name for the navigation context. Will be converted to a symbol internally.
100
+
101
+ **Returns:** `Spree::Admin::Navigation` - The navigation context instance
102
+
103
+ **Note:** Calling `register_context` multiple times with the same name returns the same instance (idempotent).
104
+
105
+ ### Custom Tab Contexts
106
+
107
+ You can create custom tab contexts for your own admin pages using `register_context`:
108
+
109
+ ```ruby config/initializers/spree.rb
110
+ Rails.application.config.after_initialize do
111
+ # Register custom tab navigation for your brands page
112
+ brand_tabs = Spree.admin.navigation.register_context(:brand_tabs)
113
+
114
+ brand_tabs.add :active_brands,
115
+ label: 'Active Brands',
116
+ url: -> { spree.admin_brands_path(status: 'active') },
117
+ position: 10,
118
+ active: -> { params[:status] == 'active' }
119
+
120
+ brand_tabs.add :archived_brands,
121
+ label: 'Archived Brands',
122
+ url: -> { spree.admin_brands_path(status: 'archived') },
123
+ position: 20,
124
+ active: -> { params[:status] == 'archived' }
125
+ end
126
+ ```
127
+
128
+ Then render the tabs in your view using the `render_tab_navigation` helper:
129
+
130
+ ```erb app/views/spree/admin/brands/index.html.erb
131
+ <%= render_tab_navigation(:brand_tabs) %>
132
+ ```
133
+
134
+ > **TIP:** Always register custom contexts in your initializer before accessing them. Attempting to access an unregistered context will raise a `NoMethodError`.
135
+
136
+ ### Listing All Contexts
137
+
138
+ You can list all registered navigation contexts:
139
+
140
+ ```ruby
141
+ # Returns an array of context names (symbols)
142
+ Spree.admin.navigation.contexts
143
+ # => [:sidebar, :settings, :brand_tabs, :inventory_tabs]
144
+ ```
145
+
146
+ ### Checking If a Context Exists
147
+
148
+ ```ruby
149
+ # Check if a context has been created
150
+ Spree.admin.navigation.context?(:brand_tabs)
151
+ # => true or false
152
+ ```
153
+
154
+ ## Creating Submenus
155
+
156
+ Add a parent item, then add child items using the `parent` option:
157
+
158
+ ```ruby config/initializers/spree.rb
159
+ sidebar_nav.add :brands,
160
+ label: :brands,
161
+ url: :admin_brands_path,
162
+ icon: 'award',
163
+ position: 35,
164
+ if: -> { can?(:manage, Spree::Brand) }
165
+
166
+ sidebar_nav.add :all_brands,
167
+ label: 'All Brands',
168
+ url: :admin_brands_path,
169
+ position: 10,
170
+ parent: :brands,
171
+ active: -> { controller_name == 'brands' }
172
+
173
+ sidebar_nav.add :brand_categories,
174
+ label: 'Brand Categories',
175
+ url: :admin_brand_categories_path,
176
+ position: 20,
177
+ parent: :brands,
178
+ active: -> { controller_name == 'brand_categories' },
179
+ if: -> { can?(:manage, Spree::BrandCategory) }
180
+ ```
181
+
182
+ > **INFO:** Parent items are automatically marked as active when any of their children are active. You don't need to manually define the `active` option for parent items.
183
+
184
+ ## Modifying Existing Navigation
185
+
186
+ ### Finding Navigation Items
187
+
188
+ ```ruby
189
+ sidebar_nav = Spree.admin.navigation.sidebar
190
+ products_nav = sidebar_nav.find(:products)
191
+ ```
192
+
193
+ ### Adding to Existing Submenus
194
+
195
+ Use the `parent` option to add an item to an existing submenu:
196
+
197
+ ```ruby
198
+ sidebar_nav.add :brands,
199
+ label: :brands,
200
+ url: :admin_brands_path,
201
+ position: 50,
202
+ parent: :products,
203
+ active: -> { controller_name == 'brands' },
204
+ if: -> { can?(:manage, Spree::Brand) }
205
+ ```
206
+
207
+ ### Removing Navigation Items
208
+
209
+ ```ruby
210
+ sidebar_nav.remove(:vendors)
211
+ ```
212
+
213
+ ### Updating Navigation Items
214
+
215
+ ```ruby
216
+ sidebar_nav.update(:products, label: 'Catalog', icon: 'shopping-cart')
217
+ ```
218
+
219
+ ### Replacing Navigation Items
220
+
221
+ ```ruby
222
+ sidebar_nav.replace(:products, label: 'Products', icon: 'package') do |products|
223
+ # Define new submenu structure
224
+ end
225
+ ```
226
+
227
+ ### Moving Navigation Items
228
+
229
+ ```ruby
230
+ # Move to specific position
231
+ sidebar_nav.move(:brands, position: 25)
232
+
233
+ # Move before another item
234
+ sidebar_nav.move(:brands, before: :products)
235
+
236
+ # Move after another item
237
+ sidebar_nav.move(:brands, after: :products)
238
+
239
+ # Move to first position
240
+ sidebar_nav.move(:brands, position: :first)
241
+
242
+ # Move to last position
243
+ sidebar_nav.move(:brands, position: :last)
244
+ ```
245
+
246
+ ## Advanced Examples
247
+
248
+ ### Navigation with Dynamic Badge
249
+
250
+ ```ruby
251
+ sidebar_nav.add :orders,
252
+ label: :orders,
253
+ url: :admin_orders_path,
254
+ icon: 'inbox',
255
+ position: 20,
256
+ active: -> { controller_name == 'orders' },
257
+ if: -> { can?(:manage, Spree::Order) },
258
+ badge: -> {
259
+ count = Spree::Order.ready_to_ship.count
260
+ count if count.positive?
261
+ },
262
+ badge_class: 'badge-warning'
263
+ ```
264
+
265
+ ### Section Dividers
266
+
267
+ ```ruby
268
+ sidebar_nav.add :settings_section,
269
+ section_label: 'Settings',
270
+ position: 90
271
+ ```
272
+
273
+ ### Dynamic URLs
274
+
275
+ ```ruby
276
+ sidebar_nav.add :store_settings,
277
+ label: :settings,
278
+ url: -> { spree.edit_admin_store_path(section: 'general-settings') },
279
+ icon: 'settings',
280
+ position: 100
281
+ ```
282
+
283
+ ### Complex Conditional Display
284
+
285
+ ```ruby
286
+ sidebar_nav.add :vendors,
287
+ label: :vendors,
288
+ url: 'https://spreecommerce.org/marketplace-ecommerce/',
289
+ icon: 'heart-handshake',
290
+ position: 35,
291
+ if: -> { can?(:manage, current_store) && !defined?(SpreeEnterprise) },
292
+ badge: 'Enterprise',
293
+ tooltip: 'Multi-Vendor Marketplace is available in the Enterprise Edition',
294
+ target: '_blank'
295
+ ```
296
+
297
+ ### Complex Active State Logic
298
+
299
+ ```ruby
300
+ sidebar_nav.add :products,
301
+ label: :products,
302
+ url: :admin_products_path,
303
+ icon: 'package',
304
+ position: 30,
305
+ active: -> {
306
+ %w[products external_categories taxons taxonomies option_types option_values
307
+ properties stock_items stock_transfers variants digital_assets].include?(controller_name)
308
+ },
309
+ if: -> { can?(:manage, Spree::Product) }
310
+ ```
311
+
312
+ ## Best Practices
313
+
314
+
315
+ - **Authorization** — Always use `if: -> { can?(...) }` to ensure users only see navigation items they have permission to access.
316
+
317
+ - **Translations** — Use symbols for labels (e.g., `label: :brands`) to support internationalization via `Spree.t`.
318
+
319
+ - **Active States** — Define clear active state logic using lambdas to highlight the current section properly.
320
+
321
+ - **Positioning** — Use consistent position intervals (e.g., 10, 20, 30) to leave room for future additions.
322
+
323
+
324
+ ### Common Positioning Reference
325
+
326
+ Main sidebar navigation positions:
327
+
328
+ - Getting Started: 5
329
+ - Home: 10
330
+ - Orders: 20
331
+ - Returns: 25
332
+ - Products: 30
333
+ - Customers: 40
334
+ - Promotions: 50
335
+ - Reports: 60
336
+ - Storefront: 70
337
+ - Integrations: 80
338
+ - Settings Section: 90
339
+ - Settings: 100
340
+ - Admin Users: 110
341
+
342
+ ### Troubleshooting
343
+
344
+ <details>
345
+ <summary>Navigation item not appearing</summary>
346
+
347
+ - Restart your server after modifying initializers
348
+ - Check authorization: ensure `if: -> { can?(...) }` returns true
349
+ - Verify the item isn't hidden by a parent's `if` condition
350
+
351
+ </details>
352
+
353
+
354
+ <details>
355
+ <summary>Active state not working</summary>
356
+
357
+ - Ensure `active:` lambda returns true/false
358
+ - Check that controller_name or other conditions match correctly
359
+ - For submenus, ensure parent uses same active logic as children
360
+
361
+ </details>
362
+
363
+
364
+ <details>
365
+ <summary>Badge not displaying</summary>
366
+
367
+ - Ensure the badge lambda returns a non-nil value
368
+ - Check that the badge value is truthy (empty strings won't display)
369
+ - For numeric badges, ensure the count is greater than 0
370
+
371
+ </details>
372
+
373
+
374
+ ---
375
+
376
+ ## Previous versions
377
+
378
+ > **WARNING:** The following documentation applies to Spree 5.1 and earlier. If you're using Spree 5.2+, please refer to the documentation above.
379
+
380
+ ### How it works
381
+
382
+ The admin navigation system works through injection points defined throughout the sidebar. You can inject custom navigation items into these predefined locations, add new top-level menu items, or create nested submenus.
383
+
384
+ ### Navigation Injection Points
385
+
386
+ The main navigation file is located at `admin/app/views/spree/admin/shared/sidebar/_store_nav.html.erb` and provides several injection points:
387
+
388
+ #### Available Injection Points
389
+
390
+ <details>
391
+ <summary>store_nav_partials</summary>
392
+
393
+ `store_nav_partials`
394
+
395
+ Injects navigation items into the main sidebar navigation, after the Reports item and before the Storefront and Integrations sections.
396
+
397
+ <img src="/images/developer/admin/store_nav_partials.png" alt="Main navigation injection point" />
398
+
399
+ This is the primary injection point for adding custom top-level navigation items.
400
+
401
+ </details>
402
+
403
+
404
+ <details>
405
+ <summary>store_products_nav_partials</summary>
406
+
407
+ `store_products_nav_partials`
408
+
409
+ Injects navigation items into the Products submenu, after the Properties item.
410
+
411
+ Use this to add product-related navigation items that logically belong under the Products section.
412
+
413
+ </details>
414
+
415
+
416
+ <details>
417
+ <summary>store_orders_nav_partials</summary>
418
+
419
+ `store_orders_nav_partials`
420
+
421
+ Injects navigation items into the Orders submenu, after the Draft Orders item.
422
+
423
+ Use this to add order-related navigation items.
424
+
425
+ </details>
426
+
427
+
428
+ <details>
429
+ <summary>store_settings_nav_partials</summary>
430
+
431
+ `store_settings_nav_partials`
432
+
433
+ Injects navigation items into the Settings section, after the Policies item.
434
+
435
+ Use this when Settings mode is active to add configuration-related items.
436
+
437
+ </details>
438
+
439
+
440
+ <details>
441
+ <summary>settings_nav_partials</summary>
442
+
443
+ `settings_nav_partials`
444
+
445
+ Injects navigation items at the end of the Settings section.
446
+
447
+ Use this to add additional settings-related navigation items.
448
+
449
+ </details>
450
+
451
+
452
+ ### Using the nav_item Helper
453
+
454
+ The `nav_item` helper method is provided by `Spree::Admin::NavigationHelper` and makes it easy to create properly formatted navigation items.
455
+
456
+ ### Method Signature
457
+
458
+ ```ruby
459
+ nav_item(label = nil, url, icon: nil, active: nil, data: {})
460
+ ```
461
+
462
+ #### Parameters
463
+
464
+ - **`label`** (`String`) — The text label for the navigation item. Can be HTML-safe content.
465
+
466
+ - **`url`** (`String`) — The URL the navigation item links to. Use the `spree.` route helper prefix.
467
+
468
+ - **`icon`** (`String`) — Optional icon name from [Tabler Icons](https://tabler.io/icons). The icon will be displayed before the label.
469
+
470
+ - **`active`** (`Boolean`) — Manually set whether the link should be marked as active. If not specified, it will be auto-detected based on the current URL.
471
+
472
+ - **`data`** (`Hash`) — Additional data attributes to add to the link element.
473
+
474
+ #### Basic Usage
475
+
476
+ ```erb
477
+ <%= nav_item(Spree.t(:custom_section), spree.admin_custom_path, icon: 'star') %>
478
+ ```
479
+
480
+ #### With Active State
481
+
482
+ ```erb
483
+ <%= nav_item(
484
+ Spree.t(:inventory),
485
+ spree.admin_inventory_path,
486
+ icon: 'boxes',
487
+ active: controller_name == 'inventory'
488
+ ) %>
489
+ ```
490
+
491
+ #### With Block Content
492
+
493
+ ```erb
494
+ <%= nav_item(nil, spree.admin_dashboard_path, icon: 'home') do %>
495
+ <%= icon 'home' %>
496
+ <%= Spree.t(:dashboard) %>
497
+ <span class="badge ml-auto">New</span>
498
+ <% end %>
499
+ ```
500
+
501
+ ### Adding a Simple Navigation Item
502
+
503
+ Let's add a new "Inventory" navigation item to the main sidebar.
504
+
505
+ #### Step 1: Create the Partial
506
+
507
+ ```bash
508
+ mkdir -p app/views/spree/admin/shared
509
+ touch app/views/spree/admin/shared/_inventory_nav.html.erb
510
+ ```
511
+
512
+ #### Step 2: Add Navigation Code
513
+
514
+ ```erb app/views/spree/admin/shared/_inventory_nav.html.erb
515
+ <% if can?(:manage, Spree::Inventory) %>
516
+ <%= nav_item(
517
+ Spree.t(:inventory),
518
+ spree.admin_inventory_index_path,
519
+ icon: 'boxes',
520
+ active: controller_name == 'inventory'
521
+ ) %>
522
+ <% end %>
523
+ ```
524
+
525
+ > **TIP:** Always wrap your navigation items with authorization checks using `can?()` to ensure users only see menu items they have permission to access.
526
+
527
+ #### Step 3: Register the Partial
528
+
529
+ Add this to your `config/initializers/spree.rb`:
530
+
531
+ **Spree 5.2+:**
532
+
533
+ ```ruby config/initializers/spree.rb
534
+ Rails.application.config.after_initialize do
535
+ Spree.admin.navigation.store << 'spree/admin/shared/inventory_nav'
536
+ end
537
+ ```
538
+
539
+ **Spree 5.1 and below:**
540
+
541
+ ```ruby config/initializers/spree.rb
542
+ Rails.application.config.spree_admin.store_nav_partials << 'spree/admin/shared/inventory_nav'
543
+ ```
544
+
545
+
546
+ #### Step 4: Add Translations
547
+
548
+ In your `config/locales/en.yml`:
549
+
550
+ ```yaml config/locales/en.yml
551
+ en:
552
+ spree:
553
+ inventory: "Inventory"
554
+ ```
555
+
556
+ #### Step 5: Restart Your Server
557
+
558
+ Restart your web server to load the initializer changes. The navigation item should now appear in the sidebar.
559
+
560
+ ### Creating Nested Navigation (Submenus)
561
+
562
+ To create a navigation item with a submenu, you need to use the `nav-submenu` class and manage the visibility based on the active state.
563
+
564
+ #### Example: Adding a Nested Menu
565
+
566
+ ```erb
567
+ <% inventory_active = %w[inventory warehouses stock_movements].include?(controller_name) %>
568
+
569
+ <% if can?(:manage, Spree::Inventory) %>
570
+ <%= nav_item(
571
+ Spree.t(:inventory),
572
+ spree.admin_inventory_index_path,
573
+ icon: 'boxes',
574
+ active: inventory_active
575
+ ) %>
576
+
577
+ <ul class="nav-submenu <% unless inventory_active %>d-none<% end %>">
578
+ <% if can?(:manage, Spree::Warehouse) %>
579
+ <%= nav_item(
580
+ Spree.t(:warehouses),
581
+ spree.admin_warehouses_path,
582
+ active: controller_name == 'warehouses'
583
+ ) %>
584
+ <% end %>
585
+
586
+ <% if can?(:manage, Spree::StockMovement) %>
587
+ <%= nav_item(
588
+ Spree.t(:stock_movements),
589
+ spree.admin_stock_movements_path,
590
+ active: controller_name == 'stock_movements'
591
+ ) %>
592
+ <% end %>
593
+
594
+ <%= render_admin_partials(:store_inventory_nav_partials) %>
595
+ </ul>
596
+ <% end %>
597
+ ```
598
+
599
+ #### Key Points for Submenus
600
+
601
+ 1. **Active State Variable**: Define a variable to track when any item in the menu group is active:
602
+ ```erb
603
+ <% inventory_active = %w[inventory warehouses stock_movements].include?(controller_name) %>
604
+ ```
605
+
606
+ 2. **Parent Navigation Item**: Use the active state variable for the parent item:
607
+ ```erb
608
+ <%= nav_item(..., active: inventory_active) %>
609
+ ```
610
+
611
+ 3. **Submenu Container**: Use the `nav-submenu` class and conditionally add `d-none` to hide when inactive:
612
+ ```erb
613
+ <ul class="nav-submenu <% unless inventory_active %>d-none<% end %>">
614
+ ```
615
+
616
+ 4. **Child Items**: Add child navigation items within the submenu:
617
+ ```erb
618
+ <%= nav_item(Spree.t(:child_item), spree.admin_child_path) %>
619
+ ```
620
+
621
+ 5. **Nested Injection Point** (Optional): Add an injection point within the submenu for further extensibility:
622
+ ```erb
623
+ <%= render_admin_partials(:store_inventory_nav_partials) %>
624
+ ```
625
+
626
+ ### Advanced Examples
627
+
628
+ #### Navigation with Badge
629
+
630
+ ```erb
631
+ <%= nav_item(nil, spree.admin_orders_path, icon: 'inbox', active: orders_active) do %>
632
+ <%= icon 'inbox' %>
633
+ <%= Spree.t(:orders) %>
634
+ <span class="badge ml-auto"><%= pending_orders_count %></span>
635
+ <% end %>
636
+ ```
637
+
638
+ #### Navigation with Complex Active Logic
639
+
640
+ ```erb
641
+ <% products_active = %w[products external_categories taxons taxonomies option_types option_values properties stock_items stock_transfers].include?(controller_name) || request.path.include?('products') %>
642
+
643
+ <%= nav_item(
644
+ Spree.t(:products),
645
+ spree.admin_products_path,
646
+ icon: 'package',
647
+ active: products_active
648
+ ) %>
649
+ ```
650
+
651
+ #### Extending Existing Submenus
652
+
653
+ To add an item to an existing submenu (e.g., Products), use the appropriate injection point:
654
+
655
+ **Create:** `app/views/spree/admin/shared/_custom_products_nav.html.erb`
656
+
657
+ ```erb
658
+ <% if can?(:manage, Spree::CustomProductFeature) %>
659
+ <%= nav_item(
660
+ Spree.t(:custom_feature),
661
+ spree.admin_custom_product_feature_path,
662
+ active: controller_name == 'custom_product_features'
663
+ ) %>
664
+ <% end %>
665
+ ```
666
+
667
+ **Register in** `config/initializers/spree.rb`:
668
+
669
+ **Spree 5.2+:**
670
+
671
+ ```ruby config/initializers/spree.rb
672
+ Rails.application.config.after_initialize do
673
+ Spree.admin.navigation.store_products << 'spree/admin/shared/custom_products_nav'
674
+ end
675
+ ```
676
+
677
+ **Spree 5.1 and below:**
678
+
679
+ ```ruby config/initializers/spree.rb
680
+ Rails.application.config.spree_admin.store_products_nav_partials << 'spree/admin/shared/custom_products_nav'
681
+ ```
682
+
683
+
684
+ ### Navigation in Settings Mode
685
+
686
+ When the admin is in "Settings mode" (the dedicated settings view), use the `settings_nav_partials` injection point:
687
+
688
+ ```erb
689
+ <% if settings_active? %>
690
+ <!-- Settings mode is active -->
691
+ <%= nav_item(Spree.t(:custom_settings), spree.edit_admin_store_path(section: 'custom-settings'), icon: 'adjustments') %>
692
+ <% end %>
693
+ ```
694
+
695
+ Register with:
696
+
697
+ **Spree 5.2+:**
698
+
699
+ ```ruby config/initializers/spree.rb
700
+ Rails.application.config.after_initialize do
701
+ Spree.admin.navigation.settings << 'spree/admin/shared/custom_settings_nav'
702
+ end
703
+ ```
704
+
705
+ **Spree 5.1 and below:**
706
+
707
+ ```ruby config/initializers/spree.rb
708
+ Rails.application.config.spree_admin.settings_nav_partials << 'spree/admin/shared/custom_settings_nav'
709
+ ```
710
+
711
+
712
+ ### Best Practices
713
+
714
+
715
+ - **Authorization** — Always use `can?()` checks to ensure users only see navigation items they have permission to access.
716
+
717
+ - **Translations** — Use `Spree.t()` for all navigation labels to support internationalization.
718
+
719
+ - **Icons** — Use consistent icons from [Tabler Icons](https://tabler.io/icons) that match Spree's design language.
720
+
721
+ - **Active States** — Define clear active state logic to highlight the current section in the navigation.
722
+
723
+ - **Route Helpers** — Always use `spree.` prefixed route helpers to reference admin routes correctly.
724
+
725
+ - **Injection Points** — Add your own injection points in submenus to allow further extensions by other developers.
726
+
727
+
728
+ ### Common Patterns
729
+
730
+ #### Multiple Controller Check
731
+
732
+ ```erb
733
+ <% active = %w[orders shipments payments].include?(controller_name) %>
734
+ ```
735
+
736
+ #### Path-based Check
737
+
738
+ ```erb
739
+ <% active = request.path.include?('products') %>
740
+ ```
741
+
742
+ #### Controller and Action Check
743
+
744
+ ```erb
745
+ <% active = controller_name == 'dashboard' && action_name == 'show' %>
746
+ ```
747
+
748
+ #### Parameters-based Check
749
+
750
+ ```erb
751
+ <% active = params[:section] == 'general-settings' %>
752
+ ```
753
+
754
+ ### Troubleshooting
755
+
756
+ <details>
757
+ <summary>Navigation item not appearing</summary>
758
+
759
+ - Ensure you've restarted your web server after adding the initializer
760
+ - Check that the authorization check (`can?()`) is passing
761
+ - Verify the partial path is correct (without `_` prefix and `.html.erb` suffix)
762
+ - Check that the route helper exists and is correct
763
+
764
+ </details>
765
+
766
+
767
+ <details>
768
+ <summary>Icon not displaying</summary>
769
+
770
+ - Verify the icon name exists in [Tabler Icons](https://tabler.io/icons)
771
+ - Check that you're using the correct parameter name: `icon:` not `icon_name:`
772
+ - Ensure the icon name is a string, e.g., `icon: 'boxes'`
773
+
774
+ </details>
775
+
776
+
777
+ <details>
778
+ <summary>Submenu not showing/hiding properly</summary>
779
+
780
+ - Ensure the active state variable includes all relevant controller names
781
+ - Check that the `nav-submenu` class is applied to the `<ul>` element
782
+ - Verify the `d-none` class is conditionally added when not active
783
+ - Make sure the parent nav item uses the same active state variable
784
+
785
+ </details>
786
+
787
+
788
+ <details>
789
+ <summary>Translation missing</summary>
790
+
791
+ - Add the translation key to your locale file
792
+ - Ensure the locale file is in the correct location
793
+ - Restart your server after adding translations
794
+ - Check for typos in the translation key
795
+
796
+ </details>
797
+
798
+
799
+ ### Related Documentation
800
+
801
+ - [Extending Admin UI](/developer/admin/extending-ui) - Learn about other UI injection points
802
+ - [Admin Tables](/developer/admin/tables) - Customize admin list views
803
+ - [Helper Methods](/developer/admin/helper-methods) - Explore other admin helper methods
804
+ - [Permissions](/developer/customization/permissions) - Understand the authorization system
805
+ - [Customization Quickstart](/developer/customization/quickstart) - Overview of all customization options