twentyseventeen 主题 header 图

This commit is contained in:
xing 2023-01-17 23:18:31 +08:00
parent 470312936c
commit a748d53f5a
16 changed files with 276 additions and 100 deletions

1
go.mod
View File

@ -16,6 +16,7 @@ require (
) )
require ( require (
github.com/elliotchance/phpserialize v1.3.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect

2
go.sum
View File

@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/elliotchance/phpserialize v1.3.3 h1:hV4QVmGdCiYgoBbw+ADt6fNgyZ2mYX0OgpnON1adTCM=
github.com/elliotchance/phpserialize v1.3.3/go.mod h1:gt7XX9+ETUcLXbtTKEuyrqW3lcLUAeS/AnGZ2e49TZs=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg= github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg=

View File

@ -2,7 +2,7 @@ package helper
import "encoding/json" import "encoding/json"
func MapToStruct[T any, M any](m M) (r T, err error) { func StrAnyMapToStruct[T any, M any](m M) (r T, err error) {
str, err := json.Marshal(m) str, err := json.Marshal(m)
if err != nil { if err != nil {
return return
@ -11,12 +11,12 @@ func MapToStruct[T any, M any](m M) (r T, err error) {
return return
} }
func StructToMap[T any](s T) (r map[string]any, err error) { func StructToAnyMap[K comparable, T any](s T) (r map[K]any, err error) {
marshal, err := json.Marshal(s) marshal, err := json.Marshal(s)
if err != nil { if err != nil {
return return
} }
r = make(map[string]any) r = make(map[K]any)
err = json.Unmarshal(marshal, &r) err = json.Unmarshal(marshal, &r)
return return
} }
@ -31,16 +31,15 @@ func MapToSlice[T any, K comparable, V any](m map[K]V, fn func(K, V) (T, bool))
return return
} }
func MapAnyToString(m map[any]any) (r map[string]any) { // MapAnyAnyToStrAny map[any]any => map[string]any 方便json转换
func MapAnyAnyToStrAny(m map[any]any) (r map[string]any) {
r = make(map[string]any) r = make(map[string]any)
for k, v := range m { for k, v := range m {
kk, ok := k.(string) kk, ok := k.(string)
if ok { if ok {
vv, ok := v.(map[any]any) vv, ok := v.(map[any]any)
if ok { if ok {
x := make(map[string]any) r[kk] = MapAnyAnyToStrAny(vv)
MapAnyToString(vv)
r[kk] = x
} else { } else {
r[kk] = v r[kk] = v
} }

View File

@ -18,7 +18,7 @@ type Me struct {
Null any Null any
} }
func TestMapToStruct(t *testing.T) { func TestStrAnyMapToStruct(t *testing.T) {
type args struct { type args struct {
m map[string]any m map[string]any
} }
@ -60,19 +60,19 @@ func TestMapToStruct(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
gotR, err := MapToStruct[Me](tt.args.m) gotR, err := StrAnyMapToStruct[Me](tt.args.m)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("MapToStruct() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("StrAnyMapToStruct() error = %v, wantErr %v", err, tt.wantErr)
return return
} }
if !reflect.DeepEqual(gotR, tt.wantR) { if !reflect.DeepEqual(gotR, tt.wantR) {
t.Errorf("MapToStruct() gotR = %v, want %v", gotR, tt.wantR) t.Errorf("StrAnyMapToStruct() gotR = %v, want %v", gotR, tt.wantR)
} }
}) })
} }
} }
func TestStructToMap(t *testing.T) { func TestStructToAnyMap(t *testing.T) {
type args[T any] struct { type args[T any] struct {
s T s T
} }
@ -113,13 +113,13 @@ func TestStructToMap(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
gotR, err := StructToMap[Me](tt.args.s) gotR, err := StructToAnyMap[string, Me](tt.args.s)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("StructToMap() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("StructToAnyMap() error = %v, wantErr %v", err, tt.wantErr)
return return
} }
if !reflect.DeepEqual(gotR, tt.wantR) { if !reflect.DeepEqual(gotR, tt.wantR) {
t.Errorf("StructToMap() gotR = %v, want %v", gotR, tt.wantR) t.Errorf("StructToAnyMap() gotR = %v, want %v", gotR, tt.wantR)
} }
}) })
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github/fthvgb1/wp-go/helper" "github/fthvgb1/wp-go/helper"
"github/fthvgb1/wp-go/internal/actions/theme"
cache2 "github/fthvgb1/wp-go/internal/pkg/cache" cache2 "github/fthvgb1/wp-go/internal/pkg/cache"
dao "github/fthvgb1/wp-go/internal/pkg/dao" dao "github/fthvgb1/wp-go/internal/pkg/dao"
"github/fthvgb1/wp-go/internal/pkg/models" "github/fthvgb1/wp-go/internal/pkg/models"
@ -202,7 +203,9 @@ func Index(c *gin.Context) {
stat = http.StatusInternalServerError stat = http.StatusInternalServerError
return return
} }
c.HTML(stat, helper.StrJoin(getTemplateName(), "/posts/index.gohtml"), ginH) t := getTemplateName()
tmlp := theme.Hook(t, c, ginH, int(h.scene))
c.HTML(stat, tmlp, ginH)
}() }()
err = h.parseParams() err = h.parseParams()
if err != nil { if err != nil {
@ -224,6 +227,7 @@ func Index(c *gin.Context) {
} }
if len(postIds) < 1 && h.category != "" { if len(postIds) < 1 && h.category != "" {
h.titleL = "未找到页面" h.titleL = "未找到页面"
h.scene = plugins.Empty404
} }
pw := h.session.Get("post_password") pw := h.session.Get("post_password")
@ -247,6 +251,7 @@ func Index(c *gin.Context) {
} }
ginH["posts"] = postIds ginH["posts"] = postIds
ginH["totalPage"] = h.getTotalPage(totalRaw) ginH["totalPage"] = h.getTotalPage(totalRaw)
ginH["currentPage"] = h.getTotalPage(h.page)
ginH["pagination"] = pagination(h.page, h.totalPage, h.paginationStep, c.Request.URL.Path, q) ginH["pagination"] = pagination(h.page, h.totalPage, h.paginationStep, c.Request.URL.Path, q)
ginH["title"] = h.getTitle() ginH["title"] = h.getTitle()
} }

View File

@ -0,0 +1,30 @@
package theme
import (
"github.com/gin-gonic/gin"
"github/fthvgb1/wp-go/internal/plugins"
"github/fthvgb1/wp-go/internal/templates/twentyseventeen"
)
var themeMap = map[string]func(*gin.Context, gin.H, int) string{}
func InitTheme() {
HookFunc(twentyseventeen.ThemeName, twentyseventeen.Hook)
}
func HookFunc(themeName string, fn func(*gin.Context, gin.H, int) string) {
themeMap[themeName] = fn
}
func Hook(themeName string, c *gin.Context, h gin.H, scene int) string {
fn, ok := themeMap[themeName]
if ok && fn != nil {
return fn(c, h, scene)
}
if _, ok := plugins.IndexSceneMap[scene]; ok {
return "twentyfifteen/posts/index.gohtml"
} else if _, ok := plugins.DetailSceneMap[scene]; ok {
return "twentyfifteen/posts/detail.gohtml"
}
return "twentyfifteen/posts/detail.gohtml"
}

View File

@ -4,6 +4,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"github/fthvgb1/wp-go/internal/actions" "github/fthvgb1/wp-go/internal/actions"
"github/fthvgb1/wp-go/internal/actions/theme"
"github/fthvgb1/wp-go/internal/cmd/route" "github/fthvgb1/wp-go/internal/cmd/route"
"github/fthvgb1/wp-go/internal/mail" "github/fthvgb1/wp-go/internal/mail"
"github/fthvgb1/wp-go/internal/pkg/cache" "github/fthvgb1/wp-go/internal/pkg/cache"
@ -11,6 +12,7 @@ import (
"github/fthvgb1/wp-go/internal/pkg/db" "github/fthvgb1/wp-go/internal/pkg/db"
"github/fthvgb1/wp-go/internal/pkg/logs" "github/fthvgb1/wp-go/internal/pkg/logs"
"github/fthvgb1/wp-go/internal/plugins" "github/fthvgb1/wp-go/internal/plugins"
"github/fthvgb1/wp-go/internal/templates"
"github/fthvgb1/wp-go/internal/wpconfig" "github/fthvgb1/wp-go/internal/wpconfig"
"github/fthvgb1/wp-go/model" "github/fthvgb1/wp-go/model"
"log" "log"
@ -46,6 +48,8 @@ func init() {
actions.InitFeed() actions.InitFeed()
cache.InitActionsCommonCache() cache.InitActionsCommonCache()
plugins.InitDigestCache() plugins.InitDigestCache()
templates.InitTemplateFunc()
theme.InitTheme()
go cronClearCache() go cronClearCache()
} }

View File

@ -11,10 +11,7 @@ import (
"github/fthvgb1/wp-go/internal/pkg/config" "github/fthvgb1/wp-go/internal/pkg/config"
"github/fthvgb1/wp-go/internal/static" "github/fthvgb1/wp-go/internal/static"
"github/fthvgb1/wp-go/internal/templates" "github/fthvgb1/wp-go/internal/templates"
"github/fthvgb1/wp-go/internal/wpconfig"
"html/template"
"net/http" "net/http"
"time"
) )
func SetupRouter() (*gin.Engine, func()) { func SetupRouter() (*gin.Engine, func()) {
@ -29,17 +26,7 @@ func SetupRouter() (*gin.Engine, func()) {
} }
} }
r.HTMLRender = templates.NewFsTemplate(template.FuncMap{ r.HTMLRender = templates.NewFsTemplate(templates.FuncMap()).SetTemplate()
"unescaped": func(s string) any {
return template.HTML(s)
},
"dateCh": func(t time.Time) any {
return t.Format("2006年 01月 02日")
},
"getOption": func(k string) string {
return wpconfig.Options.Value(k)
},
}).SetTemplate()
validServerName, reloadValidServerNameFn := middleware.ValidateServerNames() validServerName, reloadValidServerNameFn := middleware.ValidateServerNames()
fl, flReload := middleware.FlowLimit(c.MaxRequestSleepNum, c.MaxRequestNum, c.SleepTime) fl, flReload := middleware.FlowLimit(c.MaxRequestSleepNum, c.MaxRequestNum, c.SleepTime)
r.Use( r.Use(

View File

@ -6,18 +6,18 @@ import (
"github/fthvgb1/wp-go/internal/pkg/config" "github/fthvgb1/wp-go/internal/pkg/config"
"github/fthvgb1/wp-go/internal/pkg/dao" "github/fthvgb1/wp-go/internal/pkg/dao"
"github/fthvgb1/wp-go/internal/pkg/logs" "github/fthvgb1/wp-go/internal/pkg/logs"
models2 "github/fthvgb1/wp-go/internal/pkg/models" "github/fthvgb1/wp-go/internal/pkg/models"
"sync" "sync"
"time" "time"
) )
var postContextCache *cache.MapCache[uint64, common.PostContext] var postContextCache *cache.MapCache[uint64, common.PostContext]
var archivesCaches *Arch var archivesCaches *Arch
var categoryCaches *cache.SliceCache[models2.TermsMy] var categoryCaches *cache.SliceCache[models.TermsMy]
var recentPostsCaches *cache.SliceCache[models2.Posts] var recentPostsCaches *cache.SliceCache[models.Posts]
var recentCommentsCaches *cache.SliceCache[models2.Comments] var recentCommentsCaches *cache.SliceCache[models.Comments]
var postCommentCaches *cache.MapCache[uint64, []uint64] var postCommentCaches *cache.MapCache[uint64, []uint64]
var postsCache *cache.MapCache[uint64, models2.Posts] var postsCache *cache.MapCache[uint64, models.Posts]
var postMetaCache *cache.MapCache[uint64, map[string]any] var postMetaCache *cache.MapCache[uint64, map[string]any]
@ -26,9 +26,9 @@ var postListIdsCache *cache.MapCache[string, common.PostIds]
var searchPostIdsCache *cache.MapCache[string, common.PostIds] var searchPostIdsCache *cache.MapCache[string, common.PostIds]
var maxPostIdCache *cache.SliceCache[uint64] var maxPostIdCache *cache.SliceCache[uint64]
var usersCache *cache.MapCache[uint64, models2.Users] var usersCache *cache.MapCache[uint64, models.Users]
var usersNameCache *cache.MapCache[string, models2.Users] var usersNameCache *cache.MapCache[string, models.Users]
var commentsCache *cache.MapCache[uint64, models2.Comments] var commentsCache *cache.MapCache[uint64, models.Comments]
func InitActionsCommonCache() { func InitActionsCommonCache() {
c := config.Conf.Load() c := config.Conf.Load()
@ -45,25 +45,25 @@ func InitActionsCommonCache() {
postContextCache = cache.NewMapCacheByFn[uint64, common.PostContext](common.GetPostContext, c.ContextPostCacheTime) postContextCache = cache.NewMapCacheByFn[uint64, common.PostContext](common.GetPostContext, c.ContextPostCacheTime)
postsCache = cache.NewMapCacheByBatchFn[uint64, models2.Posts](common.GetPostsByIds, c.PostDataCacheTime) postsCache = cache.NewMapCacheByBatchFn[uint64, models.Posts](common.GetPostsByIds, c.PostDataCacheTime)
postMetaCache = cache.NewMapCacheByBatchFn[uint64, map[string]any](common.GetPostMetaByPostIds, c.PostDataCacheTime) postMetaCache = cache.NewMapCacheByBatchFn[uint64, map[string]any](common.GetPostMetaByPostIds, c.PostDataCacheTime)
categoryCaches = cache.NewSliceCache[models2.TermsMy](common.Categories, c.CategoryCacheTime) categoryCaches = cache.NewSliceCache[models.TermsMy](common.Categories, c.CategoryCacheTime)
recentPostsCaches = cache.NewSliceCache[models2.Posts](common.RecentPosts, c.RecentPostCacheTime) recentPostsCaches = cache.NewSliceCache[models.Posts](common.RecentPosts, c.RecentPostCacheTime)
recentCommentsCaches = cache.NewSliceCache[models2.Comments](common.RecentComments, c.RecentCommentsCacheTime) recentCommentsCaches = cache.NewSliceCache[models.Comments](common.RecentComments, c.RecentCommentsCacheTime)
postCommentCaches = cache.NewMapCacheByFn[uint64, []uint64](common.PostComments, c.PostCommentsCacheTime) postCommentCaches = cache.NewMapCacheByFn[uint64, []uint64](common.PostComments, c.PostCommentsCacheTime)
maxPostIdCache = cache.NewSliceCache[uint64](common.GetMaxPostId, c.MaxPostIdCacheTime) maxPostIdCache = cache.NewSliceCache[uint64](common.GetMaxPostId, c.MaxPostIdCacheTime)
usersCache = cache.NewMapCacheByFn[uint64, models2.Users](common.GetUserById, c.UserInfoCacheTime) usersCache = cache.NewMapCacheByFn[uint64, models.Users](common.GetUserById, c.UserInfoCacheTime)
usersNameCache = cache.NewMapCacheByFn[string, models2.Users](common.GetUserByName, c.UserInfoCacheTime) usersNameCache = cache.NewMapCacheByFn[string, models.Users](common.GetUserByName, c.UserInfoCacheTime)
commentsCache = cache.NewMapCacheByBatchFn[uint64, models2.Comments](common.GetCommentByIds, c.CommentsCacheTime) commentsCache = cache.NewMapCacheByBatchFn[uint64, models.Comments](common.GetCommentByIds, c.CommentsCacheTime)
} }
func ClearCache() { func ClearCache() {
@ -89,18 +89,18 @@ func FlushCache() {
usersCache.Flush() usersCache.Flush()
} }
func Archives(ctx context.Context) (r []models2.PostArchive) { func Archives(ctx context.Context) (r []models.PostArchive) {
return archivesCaches.getArchiveCache(ctx) return archivesCaches.getArchiveCache(ctx)
} }
type Arch struct { type Arch struct {
data []models2.PostArchive data []models.PostArchive
mutex *sync.Mutex mutex *sync.Mutex
setCacheFunc func(context.Context) ([]models2.PostArchive, error) setCacheFunc func(context.Context) ([]models.PostArchive, error)
month time.Month month time.Month
} }
func (c *Arch) getArchiveCache(ctx context.Context) []models2.PostArchive { func (c *Arch) getArchiveCache(ctx context.Context) []models.PostArchive {
l := len(c.data) l := len(c.data)
m := time.Now().Month() m := time.Now().Month()
if l > 0 && c.month != m || l < 1 { if l > 0 && c.month != m || l < 1 {
@ -117,7 +117,7 @@ func (c *Arch) getArchiveCache(ctx context.Context) []models2.PostArchive {
return c.data return c.data
} }
func Categories(ctx context.Context) []models2.TermsMy { func Categories(ctx context.Context) []models.TermsMy {
r, err := categoryCaches.GetCache(ctx, time.Second, ctx) r, err := categoryCaches.GetCache(ctx, time.Second, ctx)
logs.ErrPrintln(err, "get category ") logs.ErrPrintln(err, "get category ")
return r return r

View File

@ -44,27 +44,37 @@ func GetPostMetaByPostIds(args ...any) (r map[uint64]map[string]any, err error)
func ToPostThumb(c context.Context, meta map[string]any, host string) (r models.PostThumbnail) { func ToPostThumb(c context.Context, meta map[string]any, host string) (r models.PostThumbnail) {
if meta != nil { if meta != nil {
m, ok := meta["_thumbnail_id"] m, ok := meta["_thumbnail_id"]
if ok { if !ok {
id, err := strconv.ParseUint(m.(string), 10, 64) return
if err == nil {
mx, err := GetPostMetaByPostIds(c, []uint64{id})
if err == nil && mx != nil {
mm, ok := mx[id]
if ok && mm != nil {
f, ok := mm["_wp_attached_file"]
if ok {
ff, ok := f.(string)
if ok && ff != "" {
r.Path = ff
} }
id, err := strconv.ParseUint(m.(string), 10, 64)
if err != nil {
return
}
mx, err := GetPostMetaByPostIds(c, []uint64{id})
if err != nil || mx == nil {
return
}
mm, ok := mx[id]
if !ok || mm == nil {
return
} }
x, ok := mm["_wp_attachment_metadata"] x, ok := mm["_wp_attachment_metadata"]
if ok { if ok {
metadata, ok := x.(models.WpAttachmentMetadata) metadata, ok := x.(models.WpAttachmentMetadata)
if ok { if ok {
if _, ok := metadata.Sizes["post-thumbnail"]; ok { r = thumbnail(metadata, "post-thumbnail", host)
r.Width = metadata.Sizes["post-thumbnail"].Width }
r.Height = metadata.Sizes["post-thumbnail"].Height }
}
return
}
func thumbnail(metadata models.WpAttachmentMetadata, thumbType, host string) (r models.PostThumbnail) {
if _, ok := metadata.Sizes[thumbType]; ok {
r.Path = fmt.Sprintf("%s/wp-content/uploads/%s", host, metadata.File)
r.Width = metadata.Sizes[thumbType].Width
r.Height = metadata.Sizes[thumbType].Height
up := strings.Split(metadata.File, "/") up := strings.Split(metadata.File, "/")
r.Srcset = strings.Join(helper.MapToSlice[string](metadata.Sizes, func(s string, size models.MetaDataFileSize) (r string, ok bool) { r.Srcset = strings.Join(helper.MapToSlice[string](metadata.Sizes, func(s string, size models.MetaDataFileSize) (r string, ok bool) {
up[2] = size.File up[2] = size.File
@ -82,12 +92,5 @@ func ToPostThumb(c context.Context, meta map[string]any, host string) (r models.
r.Sizes = "(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" r.Sizes = "(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px"
} }
} }
}
}
}
}
}
}
}
return return
} }

View File

@ -52,14 +52,29 @@ func GetPostsByIds(ids ...any) (m map[uint64]models.Posts, err error) {
t = append(t, fmt.Sprintf(`<a href="/p/category/%s" rel="category tag">%s</a>`, cat, cat)) t = append(t, fmt.Sprintf(`<a href="/p/category/%s" rel="category tag">%s</a>`, cat, cat))
} }
pp.CategoriesHtml = strings.Join(t, "、") pp.CategoriesHtml = strings.Join(t, "、")
}
mm, ok := meta[pp.Id] mm, ok := meta[pp.Id]
if ok { if ok {
attMeta, ok := mm["_wp_attachment_metadata"]
if ok {
att, ok := attMeta.(models.WpAttachmentMetadata)
if ok {
pp.AttachmentMetadata = att
}
}
if pp.PostType != "attachment" {
thumb := ToPostThumb(ctx, mm, host) thumb := ToPostThumb(ctx, mm, host)
if thumb.Path != "" { if thumb.Path != "" {
pp.Thumbnail = thumb pp.Thumbnail = thumb
} }
} else if pp.PostType == "attachment" && pp.AttachmentMetadata.File != "" {
thumb := thumbnail(pp.AttachmentMetadata, "thumbnail", host)
if thumb.Path != "" {
pp.Thumbnail = thumb
} }
} }
}
if len(pp.Tags) > 0 { if len(pp.Tags) > 0 {
t := make([]string, 0, len(pp.Tags)) t := make([]string, 0, len(pp.Tags))
for _, cat := range pp.Tags { for _, cat := range pp.Tags {

View File

@ -29,7 +29,7 @@ func (p Postmeta) AttachmentMetadata() (r WpAttachmentMetadata, err error) {
} }
info, ok := unSerialize.(map[string]any) info, ok := unSerialize.(map[string]any)
if ok { if ok {
r, err = helper.MapToStruct[WpAttachmentMetadata](info) r, err = helper.StrAnyMapToStruct[WpAttachmentMetadata](info)
} }
} }
return return
@ -42,7 +42,7 @@ func AttachmentMetadata(s string) (r WpAttachmentMetadata, err error) {
} }
info, ok := unSerialize.(map[string]any) info, ok := unSerialize.(map[string]any)
if ok { if ok {
r, err = helper.MapToStruct[WpAttachmentMetadata](info) r, err = helper.StrAnyMapToStruct[WpAttachmentMetadata](info)
} }
return return
} }

View File

@ -10,8 +10,21 @@ const (
Category Category
Search Search
Detail Detail
Empty404
) )
var IndexSceneMap = map[int]struct{}{
Home: {},
Archive: {},
Category: {},
Search: {},
}
var DetailSceneMap = map[int]struct{}{
Detail: {},
Empty404: {},
}
type Func[T any] func(*Plugin[T], *gin.Context, *T, uint) type Func[T any] func(*Plugin[T], *gin.Context, *T, uint)
type Plugin[T any] struct { type Plugin[T any] struct {

View File

@ -0,0 +1,36 @@
package templates
import (
"errors"
"github/fthvgb1/wp-go/internal/wpconfig"
"html/template"
"time"
)
var funcs = template.FuncMap{
"unescaped": func(s string) any {
return template.HTML(s)
},
"dateCh": func(t time.Time) any {
return t.Format("2006年 01月 02日")
},
"getOption": func(k string) string {
return wpconfig.Options.Value(k)
},
}
func FuncMap() template.FuncMap {
return funcs
}
func InitTemplateFunc() {
}
func AddTemplateFunc(fnName string, fn any) error {
if _, ok := funcs[fnName]; ok {
return errors.New("a same name func exists")
}
funcs[fnName] = fn
return nil
}

View File

@ -15,18 +15,26 @@
<div class="custom-header" style="margin-bottom: 0px;"> <div class="custom-header" style="margin-bottom: 0px;">
<div class="custom-header-media"> <div class="custom-header-media">
<div id="wp-custom-header" class="wp-custom-header"><img src="/wp-content/themes/twentyseventeen/assets/images/header.jpg" width="2000" height="1200" alt=""></div> </div> <div id="wp-custom-header" class="wp-custom-header">
<img src="{{.HeaderImage.Path}}" width="{{.HeaderImage.Width}}" height="{{.HeaderImage.Height}}" alt="" {{if .HeaderImage.Srcset}}srcset="{{.HeaderImage.Srcset}}" {{end}} {{if .HeaderImage.Sizes}}sizes="{{.HeaderImage.Srcset}}" {{end}}>
</div>
</div>
<div class="site-branding" style="margin-bottom: 0px;"> <div class="site-branding" style="margin-bottom: 0px;">
<div class="wrap"> <div class="wrap">
<div class="site-branding-text"> <div class="site-branding-text">
<h1 class="site-title"><a href="/" rel="home">{{ "blogname"| getOption }}</a></h1> <h1 class="site-title">
<a href="/" rel="home">{{ "blogname"| getOption }}</a>
</h1>
<p class="site-description">{{"blogdescription"| getOption}}</p> <p class="site-description">{{"blogdescription"| getOption}}</p>
</div><!-- .site-branding-text --> </div><!-- .site-branding-text -->
<a href="#content" class="menu-scroll-down"><svg class="icon icon-arrow-right" aria-hidden="true" role="img"> <use href="#icon-arrow-right" xlink:href="#icon-arrow-right"></use> </svg><span class="screen-reader-text">向下滚动到内容</span></a> <a href="#content" class="menu-scroll-down">
<svg class="icon icon-arrow-right" aria-hidden="true" role="img">
<use href="#icon-arrow-right" xlink:href="#icon-arrow-right"></use>
</svg>
<span class="screen-reader-text">向下滚动到内容</span>
</a>
</div><!-- .wrap --> </div><!-- .wrap -->
</div><!-- .site-branding --> </div><!-- .site-branding -->
@ -51,7 +59,6 @@
</div> </div>
</div> </div>
{{template "layout/footer" .}} {{template "layout/footer" .}}
</body> </body>

View File

@ -0,0 +1,74 @@
package twentyseventeen
import (
"github.com/elliotchance/phpserialize"
"github.com/gin-gonic/gin"
"github/fthvgb1/wp-go/helper"
"github/fthvgb1/wp-go/internal/pkg/cache"
"github/fthvgb1/wp-go/internal/pkg/logs"
"github/fthvgb1/wp-go/internal/pkg/models"
"github/fthvgb1/wp-go/internal/plugins"
"github/fthvgb1/wp-go/internal/wpconfig"
)
const ThemeName = "twentyseventeen"
type HeaderImageMeta struct {
CustomCssPostId int `json:"custom_css_post_id,omitempty"`
NavMenuLocations []string `json:"nav_menu_locations,omitempty"`
HeaderImage string `json:"header_image,omitempty"`
HeaderImagData ImageData `json:"header_image_data,omitempty"`
}
type ImageData struct {
AttachmentId int64 `json:"attachment_id,omitempty"`
Url string `json:"url,omitempty"`
ThumbnailUrl string `json:"thumbnail_url,omitempty"`
Height int64 `json:"height,omitempty"`
Width int64 `json:"width,omitempty"`
}
func Hook(c *gin.Context, h gin.H, scene int) (r string) {
if _, ok := plugins.IndexSceneMap[scene]; ok {
r = "twentyseventeen/posts/index.gohtml"
h["HeaderImage"] = getHeaderImage(c)
} else if _, ok := plugins.DetailSceneMap[scene]; ok {
r = "twentyseventeen/posts/detail.gohtml"
}
return
}
func getHeaderImage(c *gin.Context) (r models.PostThumbnail) {
r.Path = "/wp-content/themes/twentyseventeen/assets/images/header.jpg"
r.Width = 2000
r.Height = 1200
meta, err := getHeaderMarkup()
if err != nil {
logs.ErrPrintln(err, "解析主题背景图设置错误")
return
}
if meta.HeaderImagData.AttachmentId > 0 {
m, err := cache.GetPostById(c, uint64(meta.HeaderImagData.AttachmentId))
if err != nil {
logs.ErrPrintln(err, "获取主题背景图信息错误")
return
}
if m.Thumbnail.Path != "" {
r = m.Thumbnail
}
}
return
}
func getHeaderMarkup() (r HeaderImageMeta, err error) {
mods, ok := wpconfig.Options.Load("theme_mods_twentyseventeen")
var rr map[any]any
if ok {
err = phpserialize.Unmarshal([]byte(mods), &rr)
if err == nil {
rx := helper.MapAnyAnyToStrAny(rr)
r, err = helper.StrAnyMapToStruct[HeaderImageMeta](rx)
}
}
return
}