Skip to content

Commit

Permalink
Add support for WP gallery shortcodes
Browse files Browse the repository at this point in the history
1. Parse and convert markup from WP to Hugo
2. Add custom Hugo gallery shortcode with CSS for column layouts
3. Nest individual images with figure shortcode within galleries
  • Loading branch information
aurelienpierre committed Sep 11, 2024
1 parent ce1f667 commit 358862e
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 1 deletion.
15 changes: 14 additions & 1 deletion src/wp2hugo/internal/hugogenerator/custom_shortcodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,18 @@ const _ParallaxBlurShortCode = `{{ $imgURL := .Get "src" }}
</div>
`

const _galleryShortCode = `
{{ $p := .Page }}
<div class="gallery gallery-cols-{{ .Get "cols" | default 1 }}">
{{- print .Inner | $p.RenderString -}}
</div>
`

func WriteCustomShortCodes(siteDir string) error {
return errors.Join(writeGoogleMapsShortCode(siteDir),
writeSelectedPostsShortCode(siteDir),
writeParallaxBlurShortCode(siteDir))
writeParallaxBlurShortCode(siteDir),
writeGalleryShortCode(siteDir))
}

func writeGoogleMapsShortCode(siteDir string) error {
Expand All @@ -125,6 +133,11 @@ func writeParallaxBlurShortCode(siteDir string) error {
return writeShortCode(siteDir, "parallaxblur", _ParallaxBlurShortCode)
}

func writeGalleryShortCode(siteDir string) error {
return writeShortCode(siteDir, "gallery", _galleryShortCode)
}


func writeShortCode(siteDir string, shortCodeName string, fileContent string) error {
log.Debug().
Str("shortcode", shortCodeName).
Expand Down
7 changes: 7 additions & 0 deletions src/wp2hugo/internal/hugogenerator/generate_hugo_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ type _HugoConfig struct {
GuessSyntax bool `yaml:"guessSyntax"`
Style string `yaml:"style"`
} `yaml:"highlight"`
Goldmark struct {
// Unsafe HTML is needed to nest shortcodes within each other, aka figure inside gallery
Renderer struct {
Unsafe bool `yaml:"unsafe"`
} `yaml:"renderer"`
} `yaml:"goldmark"`
}
Outputs struct {
Home []string `yaml:"home"`
Expand Down Expand Up @@ -105,6 +111,7 @@ func updateConfig(siteDir string, info wpparser.WebsiteInfo) error {
config.Markup.Highlight.CodeFences = true
config.Markup.Highlight.GuessSyntax = true
config.Markup.Highlight.Style = "monokai"
config.Markup.Goldmark.Renderer.Unsafe = true
// https://adityatelange.github.io/hugo-PaperMod/posts/papermod/papermod-features/#search-page
config.Outputs.Home = []string{"HTML", "RSS", "JSON"}
config.OutputFormats.RSS.MediaType = "application/rss+xml"
Expand Down
40 changes: 40 additions & 0 deletions src/wp2hugo/internal/hugogenerator/hugo_custom_css.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package hugogenerator

import "path/filepath"

const _customCSS = `
.gallery {
display: flex;
flex-wrap: wrap;
}
.gallery figure,
.gallery figure img {
text-align: center;
}
.gallery figure img {
margin: 1rem auto;
}
.gallery-cols-1 figure {
width: 100%;
}
.gallery-cols-2 figure {
width: 50%;
}
.gallery-cols-3 figure {
width: 33.3333333333%;
}
.gallery-cols-4 figure {
width: 25%;
}
.gallery-cols-5 figure {
width: 25%;
}
.gallery-cols-6 figure {
width: 16.666666666%;
}
`

func setupCSS(siteDir string) error {
err := appendFile(filepath.Join(siteDir, _outputCssFile), _customCSS)
return err
}
3 changes: 3 additions & 0 deletions src/wp2hugo/internal/hugogenerator/hugo_gen_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ func (g Generator) Generate() error {
if err = setupFont(*siteDir, g.fontName); err != nil {
return err
}
if err = setupCSS(*siteDir); err != nil {
return err
}
if err = WriteCustomShortCodes(*siteDir); err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions src/wp2hugo/internal/hugogenerator/hugopage/hugo_page.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ func (page *Page) getMarkdown(provider ImageURLProvider, htmlContent string, foo
converter := getMarkdownConverter()
htmlContent = improvePreTagsWithCode(htmlContent)
htmlContent = replaceCaptionWithFigure(htmlContent)
htmlContent = replaceGalleryWithFigure(provider, htmlContent)
htmlContent = replaceAWBWithParallaxBlur(provider, htmlContent)
htmlContent = strings.Replace(htmlContent, _WordPressMoreTag, _customMoreTag, 1)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package hugopage

import (
"fmt"
"regexp"
"strings"

"github.com/rs/zerolog/log"
)

// Example: [gallery size="medium" link="file" columns="4" ids="1710,1713,1712,1711"]
// Full examples : https://codex.wordpress.org/Gallery_Shortcode
// the important field to extract is "ids", but others might come in handy
// `size` is legacy from pre-responsive design and should be discarded now
// `link` is probably something to enforce in Hugo figure shortcode,
// for us it's mostly "file" to handle, since "attachment_page" makes no sense for Hugo.
var _GalleryRegEx = regexp.MustCompile(`\[gallery ([^\[\]]*)\]`)

var _idRegEx = regexp.MustCompile(`ids="([^"]+)"`)
var _colsRegEx = regexp.MustCompile(`columns="([^"]+)"`)

// TODO: should we handle `order="ASC|DESC"` when `orderby="ID"` ?
// Seems to me that people mostly order pictures in galleries arbitrarily.

// Converts the WordPress's caption shortcode to Hugo shortcode "figure"
// https://adityatelange.github.io/hugo-PaperMod/posts/papermod/papermod-faq/#centering-image-in-markdown
func replaceGalleryWithFigure(provider ImageURLProvider, htmlData string) string {
log.Debug().
Msg("Replacing gallery with figures")

htmlData = replaceAllStringSubmatchFunc(_GalleryRegEx, htmlData,
func(groups []string) string {
return galleryReplacementFunction(provider, groups)
})

return htmlData
}

func galleryReplacementFunction(provider ImageURLProvider, groups []string) string {
var output strings.Builder

// Find columns layout
cols := _colsRegEx.FindStringSubmatch(groups[1])
col_nb := "1"
if cols != nil {
col_nb = cols[1]
}

// Find image IDs
ids := _idRegEx.FindStringSubmatch(groups[1])
ids_array := strings.Split(ids[1], ",")

// TODO: maybe handle `order="ASC|DESC"` in conjunction with `orderby="..."`, so reorder ids_array here.

// We will use `figure` shortcodes nested into a `gallery` shortcode for the main layout
output.WriteString("<br>") // This will get converted to newline later on

// Opening tag :
output.WriteString(fmt.Sprintf(`{{%% gallery cols="%s" %%}}`, col_nb))

// For each image ID in WP gallery shortcode, get the URL
for _, s := range ids_array {
tmp, err := provider.GetImageInfo(s)
if tmp != nil {
src := tmp.ImageURL
// These characters create problems in Hugo's markdown
src = strings.ReplaceAll(src, " ", "%20")
src = strings.ReplaceAll(src, "_", "%5F")

title := tmp.Title

output.WriteString("<br>") // This will get converted to newline later on
output.WriteString(fmt.Sprintf(`{{< figure src="%s" title="%s" alt="%s" >}}`, src, title, title))
output.WriteString("<br>") // This will get converted to newline later on
} else {
log.Warn().
Err(err).
Str("imageID", s).
Msg("Image URL not found")
}
}

// Closing tag for main gallery shortcode
output.WriteString(`{{% /gallery %}}`)
output.WriteString("<br>") // This will get converted to newline later on
return output.String()
}

0 comments on commit 358862e

Please sign in to comment.