cms

package module
v1.12.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 1, 2025 License: AGPL-3.0 Imports: 36 Imported by: 0

README

This project is being outdated, use the new project:

New URL: https://github.com/gouniverse/cmsstore


GoLang CMS Open in Gitpod

tests Go Report Card PkgGoDev

A "plug-and-play" content managing system (CMS) for GoLang that does its job and stays out of your way.

License

This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). You can find a copy of the license at https://www.gnu.org/licenses/agpl-3.0.en.html

For commercial use, please use my contact page to obtain a commercial license.

Introduction

All of the existing GoLang CMSs require a full installations from scratch. Its impossible to just add them to an exiting Go application, and even when added feel like you don't get what you hoped for.

This package allows to add a content management system as a module dependency, which can be easily updated or removed as required to ANY Go app. It is fully self contained, and does not require any additional packages or dependencies. Removal is also a breeze just remove the module.

Features

  • Entity types
  • Templates (CMS)
  • Pages (CMS)
  • Blocks (CMS)
  • Menus (CMS)
  • Settings (CMS)
  • Translations (CMS)
  • Custom Types
  • Cache Store
  • Log Store
  • Session Store
  • Task Store (queue for background tasks)

Simplest Initialization

In its simplest initialization the CMS package accepts a standard DB instance.

However with this simplest initialization, the CMS basically has no capabilities (i.e no database stores can be accessed, no migrations are run, etc).

db, err := mainDb(utils.Env("DB_DRIVER"), utils.Env("DB_HOST"), utils.Env("DB_PORT"), utils.Env("DB_DATABASE"), utils.Env("DB_USERNAME"), utils.Env("DB_PASSWORD"))

if err != nil {
	log.Panic("Database is NIL: " + err.Error())
	return
}

if db == nil {
	log.Panic("Database is NIL")
	return
}

myCms, errCms := cms.NewCms(cms.Config{
	DbInstance:           db,
})

Initialization with entity types

myCms, errCms := cms.NewCms(cms.Config{
	DbInstance:           db,
	EntitiesAutomigrate:  true,
})

Initialization with CMS types

myCms, errCms := cms.NewCms(cms.Config{
    DbInstance:           db,
    EntitiesAutomigrate:  true,
    BlocksEnable:         true,
    MenusEnable:          true,
    PagesEnable:          true,
    TemplatesEnable:      true,
    WidgetsEnable:        true,
    Prefix:               "cms_"
})

Initialization with Settings

myCms, errCms := cms.NewCms(cms.Config{
    DbInstance:           db,
    SettingsAutomigrate:  true,
    SettingsEnable:       true,
})

Initialization with Custom Entity types

func entityList() []cms.CustomEntityStructure {
	list := []cms.CustomEntityStructure{}
	list = append(list, cms.CustomEntityStructure{
		Type:      "product",
		TypeLabel: "Product",
		AttributeList: []cms.CustomAttributeStructure{
			{
				Name:             "title",
				Type:             "string",
				FormControlLabel: "Title",
				FormControlType:  "input",
				FormControlHelp:  "The title which will be displayed to the customer",
			},
			{
				Name:             "description",
				Type:             "string",
				FormControlLabel: "Description",
				FormControlType:  "textarea",
				FormControlHelp:  "The description which will be displayed to the customer",
			},
			{
				Name:             "price",
				Type:             "string",
				FormControlLabel: "Price",
				FormControlType:  "input",
				FormControlHelp:  "The price of the product",
			},
			{
				Name:             "image_url",
				Type:             "string",
				FormControlLabel: "Image URL",
				FormControlType:  "input",
				FormControlHelp:  "The image of the product",
			},
		},
	})
	list = append(list, cms.CustomEntityStructure{
		Type:      "order",
		TypeLabel: "Order",
		AttributeList: []cms.CustomAttributeStructure{
			{
				Name:             "user_id",
				Type:             "string",
				FormControlLabel: "User ID",
				FormControlType:  "input",
				FormControlHelp:  "The ID of the user who made the purchase",
				BelongsToType:    "user",
			},
			{
				Name:             "total",
				Type:             "string",
				FormControlLabel: "Total",
				FormControlType:  "input",
				FormControlHelp:  "Total amount of the order",
			},
		},
	})
	list = append(list, cms.CustomEntityStructure{
		Type:      "order_item",
		TypeLabel: "Order",
		AttributeList: []cms.CustomAttributeStructure{
			{
				Name:             "order_id",
				Type:             "string",
				FormControlLabel: "Order ID",
				FormControlType:  "input",
				FormControlHelp:  "The ID of the order the item belongs to",
			},
			{
				Name:             "product_id",
				Type:             "string",
				FormControlLabel: "Product ID",
				FormControlType:  "input",
				FormControlHelp:  "The ID of the product that is ordered",
				BelongsToType:    "product"
			},
			{
				Name:             "quantity",
				Type:             "string",
				FormControlLabel: "Quantity",
				FormControlType:  "input",
				FormControlHelp:  "How many products are ordered (quantity) in this order item",
			},
			{
				Name:             "subtotal",
				Type:             "string",
				FormControlLabel: "Subtotal",
				FormControlType:  "input",
				FormControlHelp:  "Subtotal amount of the order item",
			},
		},
	})
	return list
}

myCms, errCms := cms.NewCms(cms.Config{
    DbInstance:           db,
    EntitiesAutomigrate:  true,
    CustomEntityList:     entityList(),
})

Cache Store

Some of the data retrieval or processing tasks performed by your application could be CPU intensive or take several seconds to complete. When this is the case, it is common to cache the retrieved data for a time so it can be retrieved quickly on subsequent requests for the same data.

CMS comes out of the box with and SQL based cache store that can be enabled on demand. The cache store is based on the following project: https://github.com/gouniverse/cachestore

  1. Initialization with Cache Store
myCms, errCms := cms.NewCms(cms.Config{
    DbInstance:        db,
    CacheAutomigrate:  true,
    CacheEnable:       true,
})
  1. Setting a cache key
isSaved, err := cms.CacheStore.Set("token", "ABCD", 60*60) // 1 hour (60 min * 60 sec)
if isSaved == false {
	log.Println("Saving failed")
	return
}
  1. Getting a cache key
token, err := cms.CacheStore.Get("token", "") // "" (default)
if token == "" {
	log.Println("Token does not exist or expired")
	return
}

CMS Setup

  • Example router (using the Chi router)
package routes

import (
	"net/http"

	"github.com/go-chi/chi/v5"
)

// Routes returns the routes of the application
func Routes(cmsRouter http.HandlerFunc) *chi.Mux {
	router := chi.NewRouter()

	router.Route("/admin", func(router chi.Router) {
		router.Use(AdminOnlyMiddleware)
		router.Get("/cms", cmsRouter)
		router.Get("/cms/{catchall:.*}", cmsRouter)
		router.Post("/cms", cmsRouter)
		router.Post("/cms/{catchall:.*}", cmsRouter)
	})

	router.Get("/", CmsController{}.Frontend)
	router.Get("/{catchall:.*}", CmsController{}.Frontend)
	router.Post("/{catchall:.*}", CmsController{}.Frontend)
	return router
}
CMS URL Patterns

The following URL patterns are supported:

  • :any - ([^/]+)
  • :num - ([0-9]+)
  • :all - (.*)
  • :string - ([a-zA-Z]+)
  • :number - ([0-9]+)
  • :numeric - ([0-9-.]+)
  • :alpha - ([a-zA-Z0-9-_]+)

Example:

/blog/:num/:any
/shop/product/:num/:any

Development Instructions

There is a development directory that allows you to quickly start working on the project or simply to preview

Instructions how to start can be found in the directory

Similar Projects Built in GoLang

Notable

Documentation

Index

Constants

View Source
const (

	// PathHome contains the path to admin CMS home page
	PathHome string = "home"

	// PathUsersHome contains the path to admin user home page
	PathUsersHome string = "user-home"

	// START: Blocks
	// PathBlocksBlockCreateAjax contains the path to admin block create page
	PathBlocksBlockCreateAjax string = "blocks/block-create-ajax"
	// PathBlocksBlockDeleteAjax contains the path to admin block delete page
	PathBlocksBlockDeleteAjax string = "blocks/block-delete-ajax"
	// PathBlocksBlockManager contains the path to admin block create page
	PathBlocksBlockManager string = "blocks/block-manager"
	// PathBlocksBlockTrashAjax contains the path to admin block trash page
	PathBlocksBlockTrashAjax string = "blocks/block-trash-ajax"
	// PathBlocksBlockUpdate contains the path to admin block update page
	PathBlocksBlockUpdate string = "blocks/block-update"
	// PathBlocksBlockUpdateAjax contains the path to admin block update page
	PathBlocksBlockUpdateAjax string = "blocks/block-update-ajax"

	// START: Menus
	// PathMenusMenuManager contains the path to admin block update page
	PathMenusMenuManager string = "menus/menu-manager"
	// PathMenusMenuCreateAjax contains the path to admin block update page
	PathMenusMenuCreateAjax string = "manus/menu-create-ajax"
	// PathMenusMenuUpdate contains the path to admin block update page
	PathMenusMenuUpdate string = "manus/menu-update"
	// PathMenusMenuItemsFetchAjax contains the path to admin block update page
	PathMenusMenuItemsFetchAjax string = "menus/menu-items-fetch-ajax"
	// PathMenusMenuItemsUpdateAjax contains the path to admin block update page
	PathMenusMenuItemsUpdateAjax string = "menus/menu-items-update-ajax"
	// PathMenusMenuItemsUpdate contains the path to admin block update page
	PathMenusMenuItemsUpdate string = "manus/menu-items-update"
	// PathMenusMenuUpdateAjax contains the path to admin block update page
	PathMenusMenuUpdateAjax string = "menus/menu-update-ajax"

	// START: Pages
	// PathPagesPageManager contains the path to admin page manager page
	PathPagesPageManager string = "pages/page-manager"
	// PathPagesPageCreateAjax contains the path to admin page update page
	PathPagesPageCreateAjax string = "pages/page-create-ajax"
	// PathPagesPageTrashAjax contains the path to admin move page to trash
	PathPagesPageTrashAjax string = "pages/page-trash-ajax"
	// PathPagesPageUpdate contains the path to admin page update page
	PathPagesPageUpdate string = "pages/page-update"
	// PathPagesPageUpdateAjax contains the path to admin page update ajax page
	PathPagesPageUpdateAjax string = "pages/page-update-ajax"

	// START: Templates
	// PathTemplatesTemplateCreateAjax contains the path to admin template create page ajax
	PathTemplatesTemplateCreateAjax string = "templates/template-create-ajax"
	// PathTemplatesTemplateManager contains the path to admin template manager page
	PathTemplatesTemplateManager string = "templates/template-manager"
	// PathTemplatesTemplateTrashAjax contains the path to template trash page
	PathTemplatesTemplateTrashAjax string = "templates/template-trash-ajax"
	// PathTemplatesTemplateUpdate contains the path to admin template update page
	PathTemplatesTemplateUpdate string = "templates/template-update"
	// PathTemplatesTemplateUpdateAjax contains the path to admin template update page ajax
	PathTemplatesTemplateUpdateAjax string = "templates/template-update-ajax"

	// START: Widgets
	// PathWidgetsWidgetManager contains the path to admin widget manager page
	PathWidgetsWidgetManager string = "widgets/widget-manager"
	// PathWidgetsWidgetCreateAjax contains the path to admin widget create page
	PathWidgetsWidgetCreateAjax string = "widgets/widget-create-ajax"
	// PathWidgetsWidgetUpdate contains the path to admin widget update page
	PathWidgetsWidgetUpdate string = "widgets/widget-update"
	// PathWidgetsWidgetUpdateAjax contains the path to admin widget update ajax
	PathWidgetsWidgetUpdateAjax string = "widgets/widget-update-ajax"

	// START: Settings
	// PathSettingsSettingManager contains the path to admin settings manager page
	PathSettingsSettingManager string = "settings/setting-manager"
	// PathSettingsSettingCreateAjax contains the path to admin settings create page
	PathSettingsSettingCreateAjax string = "settings/setting-create-ajax"
	// PathSettingsSettingDeleteAjax contains the path to admin settings delete page
	PathSettingsSettingDeleteAjax string = "settings/setting-delete-ajax"
	// PathSettingsSettingUpdate contains the path to admin settings update page
	PathSettingsSettingUpdate string = "settings/setting-update"
	// PathSettingsSettingUpdateAjax contains the path to admin settings update page
	PathSettingsSettingUpdateAjax string = "settings/setting-update-ajax"

	// START: Translations
	// PathTranslationsTranslationManager contains the path to admin translations manager page
	PathTranslationsTranslationManager string = "translations/translation-manager"
	// PathTranslationsTranslationCreateAjax contains the path to admin translations create page
	PathTranslationsTranslationCreateAjax string = "translations/translation-create-ajax"
	// PathTranslationsTranslationDeleteAjax contains the path to admin translations delete page
	PathTranslationsTranslationDeleteAjax string = "translations/translation-delete-ajax"
	// PathTranslationsTranslationTrashAjax contains the path to admin translations trash page
	PathTranslationsTranslationTrashAjax string = "translations/translation-trash-ajax"
	// PathTranslationsTranslationUpdate contains the path to admin translations update page
	PathTranslationsTranslationUpdate string = "translations/translation-update"
	// PathTranslationsTranslationUpdateAjax contains the path to admin translations update page
	PathTranslationsTranslationUpdateAjax string = "translations/translation-update-ajax"

	// START: Users
	// PathUsersUserManager contains the path to admin users manager page
	PathUsersUserManager string = "users/user-manager"
	// PathUsersUserCreateAjax contains the path to admin users create page
	PathUsersUserCreateAjax string = "users/user-create-ajax"
	// PathUsersUserDeleteAjax contains the path to admin users delete page
	PathUsersUserTrashAjax string = "users/user-trash-ajax"
	// PathUsersUserUpdate contains the path to admin users update page
	PathUsersUserUpdate string = "users/user-update"
	// PathUsersUserUpdateAjax contains the path to admin users update page
	PathUsersUserUpdateAjax string = "users/user-update-ajax"

	// START: Websites
	// PathWebsitesWebsiteManager contains the path to admin websites manager page
	PathWebsitesWebsiteManager string = "websites/website-manager"

	// START: Custom Entities
	// PathEntitiesEntityManager contains the path to admin entities update page
	PathEntitiesEntityManager string = "entities/entity-manager"
	// PathWidgetsWidgetCreateAjax contains the path to admin block update page
	PathEntitiesEntityCreateAjax string = "entities/entity-create-ajax"
	// PathWidgetsWidgetUpdate contains the path to admin block update page
	PathEntitiesEntityUpdate string = "entities/entity-update"
	// PathWidgetsWidgetUpdateAjax contains the path to admin block update page
	PathEntitiesEntityUpdateAjax string = "entities/entity-update-ajax"
)
View Source
const COLUMN_ID = "id"
View Source
const ENTITY_TYPE_BLOCK = "block"
View Source
const ENTITY_TYPE_MENU = "menu"
View Source
const ENTITY_TYPE_MENUITEM = "menuitem"
View Source
const ENTITY_TYPE_PAGE = "page"
View Source
const ENTITY_TYPE_TEMPLATE = "template"
View Source
const ENTITY_TYPE_TRANSLATION = "translation"
View Source
const ENTITY_TYPE_USER = "user"
View Source
const ENTITY_TYPE_WEBSITE = "website"
View Source
const ENTITY_TYPE_WIDGET = "widget"

Variables

This section is empty.

Functions

func ContentFindIdsByPatternPrefix

func ContentFindIdsByPatternPrefix(content, prefix string) []string

returns the IDs in the content who have the following format [[prefix_id]]

func WebpageComplete added in v1.4.1

func WebpageComplete(title, content string) *hb.HtmlWebpage

WebpageComplete returns the webpage template for the website

Types

type Cms

type Cms struct {
	Database     sb.DatabaseInterface
	CacheStore   cachestore.StoreInterface
	EntityStore  entitystore.StoreInterface
	LogStore     logstore.StoreInterface
	SessionStore sessionstore.StoreInterface
	SettingStore settingstore.StoreInterface
	TaskStore    taskstore.StoreInterface
	UserStore    entitystore.StoreInterface
	// contains filtered or unexported fields
}

Cms defines the cms

func NewCms

func NewCms(config Config) (cms *Cms, err error)

NewCms creates a new CMS instance based on the given configuration

Parameters: - config Config - the CMS configuration

Returns: - *Cms - the new CMS instance - error - any error if occurred, nil otherwise

func (*Cms) BlockFindByID

func (cms *Cms) BlockFindByID(blockID string) (types.WebBlockInterface, error)

func (*Cms) ContentRenderBlockByID

func (cms *Cms) ContentRenderBlockByID(content string, blockID string) (string, error)

ContentRenderBlockByID renders the block specified by the ID in a content if the blockID is empty or not found the initial content is returned

func (*Cms) ContentRenderBlocks

func (cms *Cms) ContentRenderBlocks(content string) (string, error)

RenderBlocks renders the blocks in a string

func (*Cms) ContentRenderShortcodes

func (cms *Cms) ContentRenderShortcodes(req *http.Request, content string) (string, error)

ContentRenderShortcodes renders the shortcodes in a string

func (*Cms) ContentRenderTranslationByIdOrHandle

func (cms *Cms) ContentRenderTranslationByIdOrHandle(content string, translationID string, language string) (string, error)

ContentRenderTranslationByIdOrHandle renders the translation specified by the ID in a content if the blockID is empty or not found the initial content is returned

func (*Cms) ContentRenderTranslations

func (cms *Cms) ContentRenderTranslations(content string, language string) (string, error)

ContentRenderTranslations renders the translations in a string

func (*Cms) FrontendHandler

func (cms *Cms) FrontendHandler(w http.ResponseWriter, r *http.Request)

FrontendHandler is the main handler for the CMS frontend.

It handles the routing of the request to the appropriate page.

If the URI ends with ".ico", it will return a blank response, as the browsers (at least Chrome and Firefox) will always request the favicon even if it's not present in the HTML.

func (*Cms) FrontendHandlerRenderAsString

func (cms *Cms) FrontendHandlerRenderAsString(w http.ResponseWriter, r *http.Request) string

FrontendHandlerRenderAsString is the same as FrontendHandler but returns a string instead of writing to the http.ResponseWriter.

It handles the routing of the request to the appropriate page.

If the URI ends with ".ico", it will return a blank response, as the browsers (at least Chrome and Firefox) will always request the favicon even if it's not present in the HTML.

If the translations are enabled, it will use the language from the request context. If the language is not valid, it will use the default language for the translations.

func (*Cms) PageFindByAlias

func (cms *Cms) PageFindByAlias(alias string) (*entitystore.Entity, error)

PageFindByAlias helper method to find a page by alias

=====================================================================

  1. It will attempt to find the page by the provided alias exactly as provided
  2. It will attempt to find the page with the alias prefixed with "/" in case of error

=====================================================================

func (*Cms) PageFindByAliasWithPatterns

func (cms *Cms) PageFindByAliasWithPatterns(alias string) (*entitystore.Entity, error)

PageFindByAliasWithPatterns helper method to find a page by matching patterns

=====================================================================

The following patterns are supported:
:any
:num
:all
:string
:number
:numeric
:alpha

=====================================================================

func (*Cms) PageRenderHtmlByAlias

func (cms *Cms) PageRenderHtmlByAlias(r *http.Request, alias string, language string) string

PageRenderHtmlByAlias builds the HTML of a page based on its alias

func (Cms) Router

func (cms Cms) Router(w http.ResponseWriter, r *http.Request)

Router shows the admin page

func (*Cms) SetFuncLayout

func (c *Cms) SetFuncLayout(funcLayout func(content string) string) *Cms

SetFuncLayout sets a layout for the CMS to display inside

func (*Cms) ShortcodeAdd

func (cms *Cms) ShortcodeAdd(shortcode ShortcodeInterface)

func (*Cms) ShortcodesAdd

func (cms *Cms) ShortcodesAdd(shortcodes []ShortcodeInterface)

func (*Cms) TemplateContentFindByID

func (cms *Cms) TemplateContentFindByID(templateID string) (string, error)

func (*Cms) TemplateFindByID

func (cms *Cms) TemplateFindByID(templateID string) (*entitystore.Entity, error)

func (*Cms) TemplateRenderHtmlByID added in v1.4.2

func (cms *Cms) TemplateRenderHtmlByID(r *http.Request, templateID string, options struct {
	PageContent         string
	PageCanonicalURL    string
	PageMetaDescription string
	PageMetaKeywords    string
	PageMetaRobots      string
	PageTitle           string
	Language            string
}) (string, error)

TemplateRenderHtmlByID builds the HTML of a template based on its ID

func (*Cms) TranslationFindByIdOrHandle

func (cms *Cms) TranslationFindByIdOrHandle(idOrHandle string, language string) (string, error)

func (*Cms) WebPageCount added in v1.6.0

func (cms *Cms) WebPageCount(options WebPageQueryOptions) (int64, error)

func (*Cms) WebPageCreate added in v1.6.0

func (cms *Cms) WebPageCreate(page types.WebPageInterface) error

func (*Cms) WebPageFindByID added in v1.6.0

func (cms *Cms) WebPageFindByID(pageID string) (types.WebPageInterface, error)

func (*Cms) WebPageList added in v1.6.0

func (cms *Cms) WebPageList(options WebPageQueryOptions) ([]types.WebPageInterface, error)

func (*Cms) WebPageUpdate added in v1.6.0

func (cms *Cms) WebPageUpdate(page types.WebPageInterface) error

type Config

type Config struct {
	Database                   sb.DatabaseInterface
	DbInstance                 *sql.DB
	DbDriver                   string
	DbDsn                      string
	CustomEntityList           []CustomEntityStructure
	Prefix                     string
	BlocksEnable               bool
	BlockEditorDefinitions     []blockeditor.BlockDefinition
	BlockEditorRenderer        func(blocks []ui.BlockInterface) string
	CacheAutomigrate           bool
	CacheEnable                bool
	EntitiesAutomigrate        bool
	LogsEnable                 bool
	LogsAutomigrate            bool
	MenusEnable                bool
	PagesEnable                bool
	SessionAutomigrate         bool
	SessionEnable              bool
	SettingsAutomigrate        bool
	SettingsEnable             bool
	Shortcodes                 []ShortcodeInterface
	TasksEnable                bool
	TasksAutomigrate           bool
	TasksQueueTableName        string
	TasksTaskTableName         string
	TemplatesEnable            bool
	TranslationsEnable         bool
	TranslationLanguageDefault string
	TranslationLanguages       map[string]string
	UsersEnable                bool
	UsersAutomigrate           bool
	DashboardEnable            bool
	WidgetsEnable              bool
	FuncLayout                 func(content string) string
}

type CustomAttributeStructure

type CustomAttributeStructure struct {
	// Name the name of the attribute
	Name string
	// Type of the attribute - string, float, int
	Type string
	// FormControlLabel label to display for the control
	FormControlLabel string
	// FormControlType the type of form control - input, textarea. etc
	FormControlType string
	// FormControlHelp help message to display for the control
	FormControlHelp string
	// BelongsToType describes a Belong To relationsip
	BelongsToType string
	// HasOneType describes a Has One relationsip
	HasOneType string
	// HasManyType describes a Has Many relationsip
	HasManyType string
}

type CustomEntityStructure

type CustomEntityStructure struct {
	// Type of the entity
	Type string
	// Label to display referencing the entity
	TypeLabel string
	// Name of the entity
	Name string
	// AttributeList list of attributes
	AttributeList []CustomAttributeStructure
	// Group to which this entity belongs (i.e. Shop, Users, etc)
	Group string
}

type LanguageKey

type LanguageKey struct{}

type ShortcodeInterface

type ShortcodeInterface interface {
	Alias() string
	Description() string
	Render(r *http.Request, s string, m map[string]string) string
}

type WebPageQueryOptions added in v1.6.0

type WebPageQueryOptions struct {
	ID        string
	IDIn      []string
	Handle    string
	Status    string
	StatusIn  []string
	Offset    int
	Limit     int
	SortOrder string
	OrderBy   string
	CountOnly bool
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL