feat: SEO field types and the complete SEO tab
This commit is contained in:
@@ -3,6 +3,7 @@ package classes
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.golem15.com/golem15/sm-seo-plugin/models"
|
||||
@@ -17,6 +18,26 @@ var EntryColumns = []string{
|
||||
"og_title", "og_description", "og_image",
|
||||
}
|
||||
|
||||
// SharedColumn is the column whose value is one per record, shared by
|
||||
// every locale row (Q-5): the social image.
|
||||
const SharedColumn = "og_image"
|
||||
|
||||
// SharedValue returns a record's shared social image: the first non-empty
|
||||
// value in locale order.
|
||||
func SharedValue(entries map[string]models.Entry) string {
|
||||
locales := make([]string, 0, len(entries))
|
||||
for locale := range entries {
|
||||
locales = append(locales, locale)
|
||||
}
|
||||
sort.Strings(locales)
|
||||
for _, locale := range locales {
|
||||
if v := entries[locale].OGImage; v != "" {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// FieldPrefix is the prefix of the SEO tab's field names (seo_title, ...),
|
||||
// so they never collide with an owner's fields.
|
||||
const FieldPrefix = "seo_"
|
||||
@@ -130,8 +151,29 @@ func (s *Service) SaveRecord(ctx context.Context, db *gorm.DB, in RecordWrite) (
|
||||
before[locale] = e
|
||||
}
|
||||
described := s.recordLocales(ctx, in.Type.Key, in.ID)
|
||||
values := in.Values
|
||||
if shared, ok := values[SharedColumn]; ok {
|
||||
// One value for every locale of the record (Q-5).
|
||||
v := ""
|
||||
for _, text := range shared {
|
||||
v = text
|
||||
}
|
||||
all := map[string]string{}
|
||||
for locale := range existing {
|
||||
all[locale] = v
|
||||
}
|
||||
for locale := range described {
|
||||
all[locale] = v
|
||||
}
|
||||
copied := RecordValues{}
|
||||
for column, perLocale := range values {
|
||||
copied[column] = perLocale
|
||||
}
|
||||
copied[SharedColumn] = all
|
||||
values = copied
|
||||
}
|
||||
touched := map[string]models.Entry{}
|
||||
for column, perLocale := range in.Values {
|
||||
for column, perLocale := range values {
|
||||
for locale, value := range perLocale {
|
||||
e, ok := touched[locale]
|
||||
if !ok {
|
||||
@@ -156,6 +198,7 @@ func (s *Service) SaveRecord(ctx context.Context, db *gorm.DB, in RecordWrite) (
|
||||
if l, ok := described[locale]; ok {
|
||||
e.URL = l.URL
|
||||
}
|
||||
e.EffectiveTitle, e.EffectiveDescription = s.effectiveOf(ctx, db, in.Type.Key, e, described[locale], locale)
|
||||
if e.ID == 0 {
|
||||
if err := db.Create(&e).Error; err != nil {
|
||||
return nil, nil, err
|
||||
@@ -181,6 +224,21 @@ func (s *Service) SaveRecord(ctx context.Context, db *gorm.DB, in RecordWrite) (
|
||||
return before, after, nil
|
||||
}
|
||||
|
||||
// effectiveOf computes an entry's effective title and description cache.
|
||||
func (s *Service) effectiveOf(ctx context.Context, db *gorm.DB, key string, e models.Entry, l pact.ContentLocale, locale string) (string, string) {
|
||||
settings, err := LoadSettings(db)
|
||||
if err != nil {
|
||||
return e.EffectiveTitle, e.EffectiveDescription
|
||||
}
|
||||
ts, err := LoadTypeSetting(db, key)
|
||||
if err != nil {
|
||||
return e.EffectiveTitle, e.EffectiveDescription
|
||||
}
|
||||
site := s.translatedSetting(ctx, db, &settings, "site_name", settings.SiteName, locale)
|
||||
fallback := s.translatedSetting(ctx, db, &settings, "default_description", settings.DefaultDescription, locale)
|
||||
return EffectiveValues(e, l, settings, ts, site, fallback)
|
||||
}
|
||||
|
||||
// recordWhat is the history description of a record's SEO in a locale:
|
||||
// "SEO of <type> “<title>” (<locale>)".
|
||||
func (s *Service) recordWhat(typ pact.MenuItemType, id string, l pact.ContentLocale, locale string) string {
|
||||
|
||||
Reference in New Issue
Block a user