# Theme Development
# Quick Start
Sample Theme Repository: https://github.com/beikeshop/beikeshop-sample-theme
You can download the sample theme first and refer to its directory structure and code for development:
# Download the sample theme
git clone https://github.com/beikeshop/beikeshop-sample-theme.git
# Copy the SampleTheme folder to the plugins/ directory of beikeshop
# Then modify and develop according to the instructions in this document
# I. Theme Architecture Overview
BeikeShop supports developing template themes in the form of plugins. The same functionality can have completely different user interfaces.
# Template Loading Mechanism
The system adopts the following template loading strategy:
- Priority is given to the enabled theme template
- If a file does not exist in the enabled template, it falls back to the default template file under the
themes/defaultdirectory
This means you only need to override the template files you want to customize; you do not need to copy all files.
# Core Directory Structure
beikeshop/
├── plugins/ # Plugin directory
│ └── YourTheme/ # Your template plugin (folder name, PascalCase)
│ ├── config.json # Plugin configuration (required)
│ ├── Bootstrap.php # Plugin bootstrap file (required)
│ ├── Resources/ # Development source files (SCSS/JS)
│ │ └── beike/shop/your_theme/
│ │ ├── css/
│ │ │ ├── bootstrap/bootstrap.scss
│ │ │ └── app.scss
│ │ └── js/
│ │ └── app.js
│ ├── Themes/ # Blade template files
│ │ └── your_theme/
│ │ ├── layout/
│ │ │ └── master.blade.php
│ │ ├── home.blade.php
│ │ └── ...
│ ├── Static/ # Static assets (published to public)
│ │ ├── image/
│ │ │ ├── logo.png # Plugin icon
│ │ │ └── theme.jpg # Theme preview image
│ │ └── public/
│ │ └── build/beike/shop/your_theme/
│ │ ├── css/
│ │ │ ├── bootstrap.css # Compiled CSS
│ │ │ └── app.css
│ │ └── js/
│ │ └── app.js
│ └── Seeders/ # Demo data (optional)
│ └── ThemeSeeder.php
├── themes/ # System template directory (auto-copied during installation)
│ └── your_theme/ # Copied from plugins/YourTheme/Themes
└── public/ # Public resource directory (auto-copied during installation)
└── plugin/your_theme/ # Copied from plugins/YourTheme/Static
# II. Creating a Theme Plugin
# 2.1 Create the Plugin Directory
Create your template folder under the plugins/ directory, for example, Fashion:
mkdir plugins/Fashion
# 2.2 Create config.json
Create config.json in the plugin root directory. This is the core configuration file for the plugin:
{
"code": "fashion",
"name": {
"zh_cn": "Fashion Theme",
"en": "Fashion Theme"
},
"description": {
"zh_cn": "A fashionable e-commerce theme",
"en": "A fashionable e-commerce theme"
},
"type": "theme",
"version": "v1.0.0",
"icon": "/image/logo.png",
"theme": "/image/theme.jpg",
"author": {
"name": "Your Name",
"email": "your@email.com"
}
}
Important Field Descriptions:
| Field | Description | Example |
|---|---|---|
code | Template unique identifier, lowercase + underscore naming | fashion, my_theme |
name | Template name, supports multiple languages | {"zh_cn": "Fashion Theme", "en": "Fashion Theme"} |
type | Must be theme | theme |
icon | Plugin icon path, relative to the Static/ directory, size 500×500 | /image/logo.png |
theme | Template preview image path, relative to the Static/ directory, size 740×856 | /image/theme.jpg |
# 2.3 Create Bootstrap.php
Create Bootstrap.php in the plugin root directory. This is the plugin bootstrap file:
<?php
namespace Plugin\Fashion;
class Bootstrap
{
public function boot()
{
// Add hook logic here
// For example: add custom CSS/JS to the page
add_hook_blade('layout.header.code', function ($callback, $output, $data) {
return view('fashion::shop.custom-code');
});
}
}
Naming Rules:
namespacemust bePlugin\YourPluginFolderName(PascalCase)- Class name must be
Bootstrap - Must contain the
boot()method
# III. Developing Template Files
# 3.1 Blade Template Files
Template files are placed under the Themes/ directory. The directory structure should be consistent with themes/default.
Development Workflow:
Copy the template files you need to modify from
themes/defaultto your plugin directory:themes/default/home.blade.php → plugins/Fashion/Themes/fashion/home.blade.phpOnly modify the files you need to customize; files that don't need modification can remain default
System loading order:
- First look for
themes/fashion/xxx.blade.php - If it doesn't exist, fall back to
themes/default/xxx.blade.php
- First look for
Example Directory Structure:
plugins/Fashion/Themes/fashion/
├── layout/
│ ├── master.blade.php # Main layout (optional override)
│ ├── header.blade.php # Header (optional override)
│ └── footer.blade.php # Footer (optional override)
├── home.blade.php # Homepage
├── category.blade.php # Category page
├── product/
│ └── product.blade.php # Product detail page
└── cart/
└── cart.blade.php # Shopping cart page
# 3.2 SCSS/CSS Styles
Style source files are placed under Resources/beike/shop/your_theme/css/.
Directory Structure:
plugins/Fashion/Resources/beike/shop/fashion/css/
├── bootstrap/
│ └── bootstrap.scss # Bootstrap custom variables
├── app.scss # Main style file
├── global.scss # Global styles
├── header.scss # Header styles
├── footer.scss # Footer styles
└── home.scss # Homepage styles
app.scss Example:
// Import bootstrap variables
@import 'bootstrap/bootstrap';
// Import module styles
@import 'global';
@import 'header';
@import 'footer';
@import 'home';
# 3.3 JavaScript
JS source files are placed under Resources/beike/shop/your_theme/js/.
Directory Structure:
plugins/Fashion/Resources/beike/shop/fashion/js/
├── app.js # Main JS file
├── common.js # Common functions
├── header.js # Header interactions
└── product.js # Product page interactions
app.js Example:
import './common';
import './header';
import './product';
# IV. Compilation Configuration (Key Point)
# 4.1 Configure webpack.mix.js
This is the most critical step. When developing a new template, you must configure the webpack.mix.js file.
Open the webpack.mix.js file in the project root directory, find the commented-out template compilation code segment (around lines 30-55), uncomment it and modify themeFileName to your plugin folder name (PascalCase):
/* If developing a new theme, uncomment the following code and set themeFileName to your theme folder name */
const themeFileName = 'Fashion'; // ← Modify to your plugin folder name (PascalCase)
const themeCode = themeFileName.replace(/([A-Z])/g,"_$1").toLowerCase().replace(/^_/,'');
// Copy template blade files to the themes directory
if (!mix.inProduction()) {
mix.copy(`plugins/${themeFileName}/Themes`, 'themes');
}
// Compile template scss/js to public/build
mix.sass(`plugins/${themeFileName}/Resources/beike/shop/${themeCode}/css/bootstrap/bootstrap.scss`, `public/build/beike/shop/${themeCode}/css/bootstrap.css`)
.then(() => {
fs.copyFileSync(`public/build/beike/shop/${themeCode}/css/bootstrap.css`, `plugins/${themeFileName}/Static/public/build/beike/shop/${themeCode}/css/bootstrap.css`);
});
mix.sass(`plugins/${themeFileName}/Resources/beike/shop/${themeCode}/css/app.scss`, `public/build/beike/shop/${themeCode}/css/app.css`)
.then(() => {
fs.copyFileSync(`public/build/beike/shop/${themeCode}/css/app.css`, `plugins/${themeFileName}/Static/public/build/beike/shop/${themeCode}/css/app.css`);
});
mix.js(`plugins/${themeFileName}/Resources/beike/shop/${themeCode}/js/app.js`, `public/build/beike/shop/${themeCode}/js/app.js`)
.then(() => {
fs.copyFileSync(`public/build/beike/shop/${themeCode}/js/app.js`, `plugins/${themeFileName}/Static/public/build/beike/shop/${themeCode}/js/app.js`);
});
Important Notes:
| Variable | Description | Example |
|---|---|---|
themeFileName | Plugin folder name, PascalCase naming | Fashion, MyTheme |
themeCode | Auto-converted code (lowercase + underscore) | fashion, my_theme |
Conversion Rules:
Fashion → fashion
MyTheme → my_theme
Fashion4 → fashion4
# 4.2 Compilation Commands
Development Phase (watch file changes, auto-compile):
npm install # Required for the first time to install dependencies
npm run watch # Watch mode, auto-compiles after file modification
Production Environment (minified build):
npm run prod # Minified compilation of CSS/JS
# 4.3 Compilation Output Description
After compilation, the following files will be automatically generated:
public/build/beike/shop/fashion/
├── css/
│ ├── bootstrap.css
│ └── app.css
└── js/
└── app.js
At the same time, through the .then() callback, the compiled files will be automatically copied to the plugin's Static/public/build/ directory:
plugins/Fashion/Static/public/build/beike/shop/fashion/
├── css/
│ ├── bootstrap.css
│ └── app.css
└── js/
└── app.js
# 4.4 ⚠️ Must Confirm Compiled Files Are Synced Before Packaging
This is a critical point that many developers easily overlook!
Before packaging and publishing the template, you must ensure:
- The compiled CSS/JS files already exist in the
Static/public/build/directory - These files will be packaged with the plugin, so users will have styles after installation
How to ensure:
Method 1 (Recommended): Use the auto-copy function configured in
webpack.mix.js- Uncomment the template compilation code
- Run
npm run prod - Compiled files will be automatically copied to the
Static/public/build/directory
Method 2 (Manual): Manually copy compiled files
- Copy files from
public/build/beike/shop/your_theme/ - Paste to
plugins/YourTheme/Static/public/build/beike/shop/your_theme/
- Copy files from
If you forget this step, users will have no styles after installing the template!
# V. Installing and Enabling the Template
# 5.1 Install the Template
- Go to Admin Panel → Plugin List
- Find your template plugin
- Click Install
During installation, the system will automatically:
- Copy Blade templates from the
Themes/directory tothemes/your_theme/ - Copy static assets from the
Static/directory to the correspondingpublic/directory
# 5.2 Enable the Template
- Go to Admin Panel → Design → Template Settings
- Find your template and click Enable
- Optional: Check "Import Demo Data" (if the template provides Seeders)
- Confirm enable
# 5.3 Visit the Storefront
After enabling, visit the storefront to see the effect of the new template.
# VI. Template Data Seeders (Optional)
If your template needs to include demo data (such as homepage layout configuration), you can use Seeders.
# 6.1 Create a Seeder
Create ThemeSeeder.php under the Seeders/ directory:
<?php
namespace Plugin\Fashion\Seeders;
use Beike\Repositories\SettingRepo;
use Illuminate\Database\Seeder;
class ThemeSeeder extends Seeder
{
public function run()
{
$homeSetting = $this->getHomeSetting();
SettingRepo::update('system', 'base', ['design_setting' => $homeSetting]);
}
private function getHomeSetting(): array
{
// Return homepage layout configuration
// Data format references the design_setting value in the settings table
return [
// ... your homepage configuration data
];
}
}
# 6.2 How to Get Homepage Configuration Data
- Configure the homepage layout in the admin design editor
- Go to the database
settingstable, find the record wherename = 'design_setting' - Copy the JSON data from the
valuefield - Use a tool to convert JSON to PHP array: https://uutool.cn/json2php/
- Put the converted array into the
getHomeSetting()method
# 6.3 Import Data When Enabling
When users enable the template in the admin panel, check the "Import Demo Data" option, and the system will automatically run the Seeder to import data.
# VII. Static Asset Management
# 7.1 Static Directory Structure
plugins/Fashion/Static/
├── image/
│ ├── logo.png # Plugin icon (displayed in admin plugin list)
│ └── theme.jpg # Theme preview image (displayed on template settings page)
├── public/
│ └── build/beike/shop/fashion/
│ ├── css/ # Compiled CSS (must include)
│ └── js/ # Compiled JS (must include)
└── catalog/fashion/ # Images used by the template (banner, icon, etc.)
└── demo/
# 7.2 Accessing Assets
Access static assets in templates:
{{-- Access plugin static files --}}
<img src="{{ plugin_asset('fashion', 'image/logo.png') }}">
<img src="{{ asset('plugin/fashion/catalog/fashion/demo/banner.jpg') }}">
{{-- Access compiled CSS/JS (automatically loaded by the system) --}}
{{ mix('/build/beike/shop/fashion/css/app.css') }}
{{ mix('/build/beike/shop/fashion/js/app.js') }}
# 7.3 Responsive Images and Cached Sizes
Supported version
BeikeShop 3.0.0.12 and later.
image_srcset() generates cached copies of an image at different widths. The browser selects a suitable version based on the displayed width and screen pixel density. Merchants upload once, and both themes and plugins can use this feature.
Shrinking an image with CSS alone still downloads the original large file. Responsive images can reduce download size, save bandwidth, and improve loading speed while keeping images sharp on high-density screens.
# Usage
For example, an image takes the full width on mobile and half the width on desktop:
@php
$imagePath = 'image/catalog/banner.jpg';
@endphp
<img
src="{{ image_origin($imagePath) }}"
srcset="{{ image_srcset($imagePath) }}"
sizes="(min-width: 992px) 50vw, 100vw"
alt="Promotional banner"
>
Replace $imagePath with your image path, such as $content['image']['src'] from a page builder module.
Pass the original image path relative to public/. Do not convert it to a full URL with image_origin() or asset() first, or pass a thumbnail URL.
| Attribute | Purpose |
|---|---|
src | The existing image URL, used as a fallback |
srcset | Candidate URLs at different widths, generated by image_srcset() |
sizes | The expected display width, which you specify to match the layout |
vw is a percentage of the viewport width. For example, 50vw means half the viewport width. Common values:
| Layout | sizes |
|---|---|
| Full-width banner | 100vw |
| One column on mobile, two on desktop | (min-width: 992px) 50vw, 100vw |
| Two columns on mobile, four on desktop | (min-width: 992px) 25vw, 50vw |
| Fixed 600px on desktop, full width on mobile | (min-width: 992px) 600px, 100vw |
These are estimates. Adjust them for your container width, columns, and breakpoints. The browser uses sizes and pixel density to choose an image; it does not download every candidate.
# Cache Rules
- Calling
image_srcset()generates missing cached sizes. Later requests reuse them. No changes to uploads or the database are needed. - Candidate widths are 480, 768, 1024, 1440, and 1920px. Only sizes smaller than the original are generated; the original is the largest candidate.
- Images keep their aspect ratio, without cropping, padding, or upscaling. A 720px-wide original, for example, only gets a 480px cached copy.
- Cached files are stored in
public/cache/. When the original's modification time advances, cached sizes are regenerated and the?v=parameter in their URLs is updated. - The first request takes extra time to generate missing sizes. Generating files on the server does not mean the browser downloads them.
# Shared Blade Partial (Optional)
You can also output the attributes with design._responsive_image:
<img
src="{{ image_origin($imagePath) }}"
@include('design._responsive_image', [
'image' => ['image_srcset' => image_srcset($imagePath)],
'sizes' => '(min-width: 992px) 50vw, 100vw',
])
alt="Promotional banner"
>
The partial only outputs attributes; it does not generate cached files. If there are no candidates, it omits srcset and sizes. You can use image_srcset() directly without this partial.
# Notes
- Supports local JPG, JPEG, PNG, and static WebP images, preserving PNG transparency. Publish bundled plugin images under
public/first. - Remote URLs, GIF, animated WebP, SVG, video, and images that cannot be processed return no candidates and continue loading through
src. - Any theme can use this feature. Existing
image_origin(),image_resize(), and image fields remain available, so older themes can keep their existing code. - This feature optimizes image file sizes. It does not change the layout, provide separate mobile compositions, or add lazy loading. For images below the fold, use
loading="lazy"or your existing lazy loading solution separately.
# VIII. Packaging and Publishing
# 8.1 Pre-Packaging Checklist
- [ ] All SCSS/JS have been compiled, and compiled files are in
Static/public/build/ - [ ]
logo.pngandtheme.jpghave been replaced with your own assets - [ ]
config.jsoninformation is complete and accurate - [ ]
Bootstrap.phpnamespace is correct - [ ] Template file paths are correct (
Themes/your_theme/) - [ ] Test installation, enable, and switch functions are working properly
# 8.2 Packaging
Package the plugin folder as a ZIP archive:
cd plugins
zip -r Fashion.zip Fashion/
# 8.3 Publishing
- Log in to the BeikeShop official website
- Go to User Center → Plugin Marketplace
- Upload the ZIP package to publish
- Other users can purchase and install it from the admin plugin marketplace
# IX. Frequently Asked Questions
# Q1: No styles after template installation?
Cause: The compiled CSS/JS files are not included in the plugin's Static/public/build/ directory.
Solution:
- Ensure the template compilation code in
webpack.mix.jsis uncommented - Run
npm run prodto compile - Confirm that compiled files exist under
plugins/YourTheme/Static/public/build/
# Q2: Modified SCSS but no changes on the storefront?
Cause: Not recompiled or cache not refreshed after compilation.
Solution:
- Use
npm run watchin the development phase to listen for auto-compilation - Wait a few seconds after modification for auto-compilation to complete
- Refresh the browser (may need force refresh Ctrl+Shift+R)
# Q3: Template file modifications not taking effect?
Cause: Blade template cache not cleared.
Solution:
php artisan view:clear
php artisan cache:clear
# Q4: How to override only some template files?
You don't need to copy all files. The system will first look for files under themes/your_theme/, and if they don't exist, fall back to themes/default/. So you only need to override the files you need to modify.
# Q5: What is the difference between themeFileName and themeCode?
themeFileName: Plugin folder name, PascalCase naming, e.g.,FashionthemeCode: Template unique identifier, lowercase + underscore, e.g.,fashion- The two are automatically converted via regex; usually you only need to modify
themeFileName
# X. Best Practices
- Only override needed files: Don't copy all default template files, only override the ones you need to modify
- Keep code clean: Follow the project's existing coding style
- Manage versions properly: Modify the
versioninconfig.jsonfor each release update - Test multilingual support: Ensure the template displays correctly in different languages
- Responsive design: Ensure the template displays well on mobile devices
- Performance optimization: Use WebP format for images, compress CSS/JS before publishing
- Backup data: Back up existing configuration data before enabling a new template
# Appendix: Naming Convention Quick Reference
| Item | Naming Rule | Example |
|---|---|---|
| Plugin folder | PascalCase | Fashion, MyTheme |
| config.json code | lowercase + underscore | fashion, my_theme |
| namespace | Plugin\FolderName | Plugin\Fashion |
| themeCode | lowercase + underscore | fashion |
| Resource path | lowercase + underscore | beike/shop/fashion/css/ |
| Blade file | lowercase + underscore | home.blade.php |