Как я перенес свой сайт WordPress на страницы GitHub

Как я перенес свой сайт WordPress на страницы GitHub

6 января 2023 г.

Я начал свой первый блог в 2010 году. Использование WordPress было очевидным в то время (это было до HackerNoon и Medium). Это был хороший выбор, потому что он прост в использовании и для него существуют тысячи тем и плагинов.

WordPress — отличный движок, но у него есть свои недостатки. Он требователен к ресурсам, и существует множество уязвимостей, связанных с WordPress. Одним из возможных решений является размещение всего сайта за CloudFront. или любой другой CDN.

CDN хорошо масштабируется и обеспечивает безопасность сайта, но в моем случае блог был только архивом, и я не хотел, чтобы мой сервер работал. Именно поэтому я выбрал страницы GitHub.

GitHub Pages — это «хостинг для бедных». Это бесплатно, и вы можете указать на него свой домен.

Недостатком этого является то, что он может размещать только статические сайты, поэтому мне пришлось создать статический сайт из моего блога WordPress.

К счастью, WordPress может экспортировать (Инструменты/Экспорт в админке) весь контент сайта в файл XML, поэтому единственное, что мне нужно было сделать, это разработать простой генератор статического сайта, который генерирует контент из экспорта.

Я выбираю TypeScript для разработки, потому что я знаком с ним, и для этого есть много классных и простых в использовании JS-библиотек.

Прежде всего, мне нужно было найти простой и удобный XML-парсер. После непродолжительного поиска в Google я нашел fast-xml-parser. Этот синтаксический анализатор создает дерево объектов JS из XML, которое можно легко обрабатывать.

Еще одна вещь, которая мне была нужна, — это простой механизм шаблонов. Для этой цели лучше всего подходит ejs. Его легко освоить, потому что вы можете просто встроить свой JS в код HTML, а также быстро, потому что в фоновом режиме движок компилирует ваш шаблон в JS.

Для небольших проектов я не могу представить себе более простое и лучшее решение.

У меня было все, что мне нужно, поэтому я начал разрабатывать свой небольшой генератор статических сайтов.

Чтобы создать шаблоны ejs, я просто загрузил HTML-файлы, созданные WordPress, и добавил к ним теги ejs. Я создал 2 шаблона. Один для сообщений и один для оглавления.

Структура экспорта XML очень проста. По сути, это RSS-канал, созданный из элементов. У каждого элемента есть тип (пост, вложение и т. д.), но мне нужны были только посты и вложения. Код выглядит так:

(async function () {
    const parser = new XMLParser();
    let wp_export = parser.parse(readFileSync('wordpress-export.xml'));
    let posts = wp_export.rss.channel.item;

    let pinned_posts: any[] = []
    let post_list: any[] = []
    for (const post of posts) {

        // download attachments
        if (post['wp:post_type'] == 'attachment') {
            const url = post['wp:attachment_url'];
            for (const post_meta of post['wp:postmeta']) {
                if (post_meta['wp:meta_key'] == '_wp_attached_file') {
                    const file_path = post_meta['wp:meta_value']
                    const full_path = `wp-content/uploads/${file_path}`
                    mkdirSync(dirname(full_path), { recursive: true });
                    const file = createWriteStream(full_path);
                    http.get(url, (resp) => {
                        resp.pipe(file);
                        file.on("finish", () => {
                            file.close();
                        });
                    })
                }
            }
        }

        // generate post page if it's published
        if (post['wp:post_type'] == 'post' && post['pubDate']) {
            post['content:encoded'] = post['content:encoded'].split(/r?n|r|n/g).reduce((accumulator: string, currentValue: string) => accumulator + `<p>${currentValue}</p>`)

            const content = await ejs.renderFile("template.ejs", { post: post }, { async: true })
            mkdirSync(`archives/${post['wp:post_id']}`, { recursive: true });
            writeFileSync(`archives/${post['wp:post_id']}/index.html`, content)

            const element = {
                id: post['wp:post_id'],
                title: post.title,
                summary: truncate(post['content:encoded'].replace(/<[^>]*>?/gm, ''), 300)
            }

            if (pinned_post_ids.includes(post['wp:post_id'])) {
                pinned_posts.push(element)
            } else {
                post_list.push(element)
            }
        }
    }

    // generate toc
    pinned_posts.sort((a, b) => { return b.id - a.id })
    let merged_posts = pinned_posts.concat(post_list.sort((a, b) => { return b.id - a.id }))

    // readme.md
    let readme = `
# my-wordpress-blog
This is a backup of my Wordpress blog. (http://lf.estontorise.hu/)

`
    for (const post of merged_posts)
        readme += `[${post.title}](https://thebojda.github.io/my-wordpress-blog/archives/${post.id})nn`
    writeFileSync('README.md', readme)

    // index.html
    const content = await ejs.renderFile("template_toc.ejs", { posts: merged_posts }, { async: true })
    writeFileSync(`index.html`, content)
})()

Код перебирает элементы и проверяет их тип. Если тип — «вложение», то он считывает значение метаданных «_wp_attached_file», которое содержит URL-адрес вложения, и загружает его с помощью модуля HTTP.

Если тип элемента «публикация» и он опубликован (pubDate не пусто), сгенерируйте страницу. Содержимое страницы находится в теге «content:encoded» в формате HTML с небольшим искажением.

Каждая строка представляет собой отдельный абзац, поэтому вам необходимо преобразовать разрывы строк в абзацы. Это делается с помощью следующей строки кода:

post['content:encoded'] = 
  post['content:encoded']
  .split(/r?n|r|n/g)
  .reduce((accumulator: string, currentValue: string) => 
    accumulator + `<p>${currentValue}</p>`)

10 лет назад, когда я начинал свой блог, я ничего не знал о SEO, поэтому ссылки на посты выглядели так: …/archives/123, где последняя цифра — это идентификатор поста.

В лучшем случае URL поста будет более выразительным и содержит ключевые слова, но в обоих случаях вы столкнетесь с проблемой, что GitHub Pages не поддерживает HTML-страницы без расширения «.html».

Если вы загрузите файл HTML без расширения, браузер загрузит файл, а не покажет его. По этой причине вам необходимо преобразовать эти URL-адреса в каталоги, содержащие файл index.html.

Например, /archives/123 необходимо преобразовать в /archives/123/index.html. С этой новой структурой все работает как часы.

Последний блок кода генерирует ToC HTML и файл readme.md. Второй может быть очень полезен, если кто-то найдет вашу страницу на GitHub, потому что он может легко перейти к вашим сообщениям.

Когда создание статической страницы завершено, я просто загрузил свой сайт на GitHub и включил страницы GitHub в настройках.

После того, как я установил запись CNAME для администратора моего провайдера DNS, GitHub проверил ее. Установив флажок Enforce HTTPS, GitHub сгенерировал HTTPS-сертификат, и через некоторое время сайт был готов. Здесь вы можете посмотреть результат: https://lf.estontorise.hu.

Блог на венгерском языке, поэтому вы, вероятно, не поймете содержание, но вы можете видеть, что все работает хорошо, а URL-адреса совпадают с URL-адресами WordPress.

Как я уже сказал, этот блог — всего лишь архив, и я не планирую создавать новые записи, но если бы я хотел, я мог бы установить свой движок WordPress на свой локальный компьютер.

Я мог бы писать новые сообщения и обновлять только что созданные страницы в репозитории, поэтому, если вы хотите использовать WordPress для ведения блога и GitHub для размещения страниц, это также возможно.

Это был мой короткий путь от WordPress до GitHub Pages; Я надеюсь, что эта короткая статья поможет вам перенести свой собственный блог, если вы хотите.

(Вы можете найти все в моем репозитории GitHub.)


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE