Version Control with Schedule
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


The Publish2 Plugin is the successor to Publish. It generalizes publishing using 3 important modules:

  • Visible: to flag an object be online/offline
  • Schedule: to schedule objects to be online/offline automatically
  • Version: to allow an object to have more than one copies and chain them together

You can read the Introducing Publish2 blog to understand our design idea in detail.


First, add Publish2 fields to the model. You can choose the module you need, we provide composability here. Please note that it requires GORM as ORM.

type Product struct {


Then, register database callback.

var db *gorm.DB

See here for callback details.

Last, Setup QOR Admin

import (

func init() {
  admin.New(&qor.Config{DB: db.DB.Set(publish2.VisibleMode, publish2.ModeOff).Set(publish2.ScheduleMode, publish2.ModeOff)})

Now, start your application, you should see the Publish2 UI has been displayed in QOR Admin UI.

Publish2 UI intro

The Publish2 section will be added to the index and new/edit page.

Demo Site

How to publish a product immediately

Tick the Publish ready option and leave Schedule Start At and Schedule End At blank.

How to schedule to publish a product

Fill the Schedule Start At and Schedule End At fields.

The Publish2 section in index page

How to make a new version of a product

Click the ... icon(C), you can see a "Create new version" button in the popup.

How to view all versions of a product

Click the clock icon(B) to toggle all versions panel.

Which version of a product will be live if there’re many version

In all versions panel, the one with green circle(A) icon is the live version.

Advanced usage

Disable callbacks

Depend on the modules you used, Publish2 callback attaches different SQL conditions to your object queries.

This is a SQL sample of select product with language_id is 6. All 3 modules are integrated with Product.

SELECT * FROM `products`  WHERE (language_id = '6') AND ((, `products`.version_priority) IN (SELECT, MAX(`products`.version_priority) FROM `products` WHERE (scheduled_start_at IS NULL OR scheduled_start_at <= '2017-02-13 02:04:09') AND (scheduled_end_at IS NULL OR scheduled_end_at >= '2017-02-13 02:04:09') AND publish_ready = 'true' AND deleted_at IS NULL GROUP BY ORDER BY `products`.`id`, `products`.version_priority DESC
  • Visible: publish_ready = 'true'
  • Version: (, products.version_priority) IN (SELECT, MAX(products.version_priority))
  • Schedule: (scheduled_start_at IS NULL OR scheduled_start_at <= 'CURRENT_TIME') AND (scheduled_end_at IS NULL OR scheduled_end_at >= 'CURRENT_TIME')

Sometimes you may need do a pure query without Publish2 conditions. You disable callbacks by

db.DB.Set(publish2.VersionMode, publish2.VersionMultipleMode).Set(publish2.VisibleMode, publish2.ModeOff).Set(publish2.ScheduleMode, publish2.ModeOff)

The Set(publish2.VersionMode, publish2.VersionMultipleMode) means use VersionMultipleMode in this query. The default VersionMode is single version mode. The difference between single and multiple is the single mode always query the live version from all versions, the multiple mode queries all versions.

Customize default version name

The default version name is Default. To overwrite it, you can use

publish2.DefaultVersionName = "1.0"

Digging deeper: Modules of publish2


Visible module controls the visibility of the object by PublishReady.

type Visible struct {
  PublishReady bool


Schedule module schedules objects to be online/offline automatically by ScheduledStartAt and ScheduledEndAt.

type Schedule struct {
  ScheduledStartAt *time.Time `gorm:"index"`
  ScheduledEndAt   *time.Time `gorm:"index"`
  ScheduledEventID *uint

type ScheduledEvent struct {
  Name             string
  ScheduledStartAt *time.Time
  ScheduledEndAt   *time.Time

If an object has PublishReady set to true and current date is inside the range between ScheduledStartAt and ScheduledEndAt, it will be visible. Otherwise, it is invisible.

Manage the date range one by one is inefficient, so we added ScheduledEvent to manage them. Imagine black Friday and Christmas are pre-created in the system, All you need to do is set a price of the product for these holidays.

We have integrated an UI for the ScheduledEvent at QOR Admin > Sidebar > Publishing > Events.


Version module allow one object to have multiple copies, with Schedule, you can schedule different prices of a product for a whole year.

type Version struct {
  VersionName     string `gorm:"primary_key"`
  VersionPriority string `gorm:"index"`

The VersionName will be the primary key of the object, So if you set a new VersionName for an object, means you will create a new copy. To set a new version name. We have obj.SetVersionName("new name"). When an object has multiple versions the database would looks like:

id version_name name
1 v1 Product - v1
1 v2 Product - v2

The VersionPriority represents the priority of current version. The rule when different versions have overlapped schedule range is, the newer the higher. For example, product A has version 1 for the Christmas(12-20 ~ 12-31) and version 2 for the New Year holiday(12-30 ~ 1-3). At 12-31, the version 2 will be the visible one.


Released under the MIT License.