如何使用 Next.js 和 Headless WordPress + SEO 构建网站的详细指南 - 2023 Web 开发

2025-06-07

如何使用 Next.js 和 Headless WordPress + SEO 构建网站的详细指南 - 2023 Web 开发

如果您还没有听说过 Next.js 和 WordPress,请不要担心 - 您可以查看我提供的链接以了解有关它们的更多信息。

在本文中,我们将共同探索Headless WordPressNext.js的强大功能,这两项技术近年来日益流行。通过结合使用它们,我们可以创建一个不仅速度惊人,而且 SEO 友好且用户体验卓越的网站。本指南非常适合经验丰富的开发人员和刚刚起步的开发者,因为我将提供所有必要的知识和工具,帮助您在 2023 年创建一流的网站。

在本文中,我将使用 Next.js 和 Headless WordPress 构建一个简单的博客。您可以通过提供的链接查看最终成品,代码可以在 GitHub 仓库中找到。

虽然 WordPress 是一个著名的内容管理系统,但并不是每个人都熟悉 Headless WordPress - 我将介绍它是什么以及它为什么重要。

什么是 Headless WordPress?

在传统的 WordPress 设置中,内容管理系统 (CMS) 和前端紧密耦合。本质上,WordPress 同时处理用户交互的内容管理和呈现。然而,有了 Headless WordPress,我们拥有了一种全新的平台使用方式,将 CMS 与前端呈现层分离。这种方法允许我们开发人员将 CMS 用作内容存储库,类似于后端,并使用提供的 API 在前端根据需要获取内容。最棒的是,我们不再局限于使用 WordPress 作为前端,而是可以选择任何我们喜欢的技术,例如 React、Vue.js、Angular,或者像我们这样,Next.js。

那么它有什么好处呢?嗯,确实非常惊人。作为开发者,这项技术使我们能够构建具有更高灵活性、更高性能以及更好地分离 CMS 和前端之间关注点的应用程序。我们可以构建自定义的高性能前端,同时仍然充分利用 WordPress 强大的内容管理功能。


在此设置中,我们将介绍以下一些内容:

  • 使用 TypeScript 设置 Next.js。
  • 使用 Flywheel 在本地设置 WordPress,这将使我们能够建立用于安装 WordPress 的服务器。WordPress 安装。您也可以使用 XAMPP、WAMP 或任何其他熟悉的工具。
  • 下载和配置插件。
  • 连接我们的 WordPress 并建立我们的博客。
  • 部署我们的博客。
  • 优化博客的 SEO。(需要有效的 URL)。

准备好了吗?开始吧!

使用 TypeScript 设置 Next.js

选项 1(推荐)

如果您想加入我或已经了解此内容,您可以获取我在 GitHub 上制作的入门模板。它包含 React 组件和项目样式等实用功能。只需运行npm installyarn install安装依赖项即可。这是入门模板的链接:点击此处获取

选项 2

但是,如果您愿意付出更多努力并自行使用 TypeScript 设置 Next.js,请继续阅读。

首先,在你的桌面或任何你喜欢的位置为这个项目创建一个新文件夹。我把它命名为“the-headless-blog”。🧐

使用 TypeScript 启动 Next.js 项目的最快方法是使用npx create-next-app带有--typescript标志的命令。在您喜欢的 IDE 中打开项目文件夹,然后在终端上运行以下命令:

npx create-next-app@latest --typescript

系统会提示你回答一些关于项目配置的问题。为了方便后续操作,我选择了以下选项:

  1. 您的项目名称是什么? - 。(“。”,指定使用我的文件夹名称作为项目名称。您可以输入您选择的名称)
  2. 您想在此项目中使用 ESLint 吗? - 是的
  3. src/您想在此项目中使用目录吗? - 否
  4. 您想app/在此项目中使用实验目录吗? - 否
  5. 您想要配置什么导入别名? - @/*

让我们继续前进。

本地 WordPress 安装和设置

请随意跳过此部分。

Local by Flywheel 是一款轻松的本地开发 WordPress 网站的工具。它与 XAMPP 和 WAMP 等工具非常相似,但我最常用的还是它。您可以在这里了解更多信息并免费下载。

要开始创建新站点,请打开 Local by Flywheel,导航到窗口左下角的绿色加号图标。点击该图标后,系统会提示您选择创建新站点的选项。选择“创建新站点”选项,然后点击“继续”。

图片描述

之后,您将进入一个新屏幕,您可以在其中输入网站名称。只需输入您喜欢的名称,然后点击“继续”按钮即可。

然后,您将看到一个选择环境的选项。通常,首选选项即可,但如果您希望自定义环境,请选择“自定义”选项。

图片描述

下一步是输入您的 WordPress 凭据,包括用户名、密码和电子邮件地址。输入完成后,点击“添加网站”按钮。

图片描述

留出一些时间来部署站点,一旦该过程完成,如果尚未启动,请单击“启动站点”按钮。

图片描述

图片描述

要访问 WordPress 仪表板,请点击“WP Admin”按钮,然后使用您之前创建的凭据登录。恭喜!您的 WordPress 安装现已完成。

WordPress 仪表板

下载和配置插件

回想一下,我们的计划是仅将 WordPress 用作内容存储库,然后通过 API 获取内容。默认情况下,WordPress 提供了一个基本的REST API,用于检索和管理内容和数据。但是,在本项目中,我们将使用WPGraphQL插件来增强性能并满足个人偏好。

  • WPGraphQL:这是一个开源且免费的 WordPress 插件,为您的 WordPress 网站提供用户友好的 GraphQL API。我们将使用 Facebook 开发的 API 查询语言 GraphQL,而不是标准的 WordPress REST API。它允许您仅从 API 请求所需的数据,从而提高应用程序的速度和效率。借助此插件,我们将能够使用 GraphQL 查询从 WordPress 中检索数据。点击此处了解更多关于 GraphQL 查询语言的信息。

要安装,请导航到 WordPress 仪表板上的插件目录,然后搜索“graphql”。继续安装并激活 WPGraphQL 插件。截至撰写本文时,该插件的活跃安装量已超过 20,000 个。

图片描述

我们先暂停一下,在 WordPress 中生成至少三到五篇虚拟文章。每篇文章应该包含标题、精选图片和摘录。稍后我们会在前端检索这些文章。

虚拟帖子

连接我们的 WordPress 并建立我们的博客

在 Next.js 设置部分,我添加了一个获取入门模板的链接,地址如下。入门模板包含我将要使用的 React 组件和样式的有用代码,并且我还集成了TailwindCSS以减少需要编写的 CSS 代码量。

我将主要专注于将我们的项目连接到 WordPress,从那里提取文章并显示在屏幕上。之后,我将深入研究 SEO 方面的内容。

要将 WordPress 链接到我们的项目,请转到您的 WordPress 仪表板。如果您已安装并激活了 WPGraphQL 插件,它现在应该会显示在仪表板上,并带有一个标签“GraphQL”。点击它,然后转到 GraphQL 设置页面。

GraphQL 设置页面

在设置中的“WPGraphQL 常规设置”页面,您可以找到将 WordPress 连接到项目所需的 GraphQL 端点。此端点允许我们从前端与 WordPress 通信并根据需要获取内容。只需复制该端点即可,其 URL 应以 http 或 https 开头。

WpGraphQL 端点

回到项目文件夹,.env在主目录中创建一个文件。该文件用于存储环境变量,例如 API 密钥、数据库凭据或我们刚刚复制的端点。

创建文件后,为端点添加一个密钥并保存文件。您可以将其命名为NEXT_PUBLIC_WORDPRESS_API_ENDPOINT。无论命名如何,请确保其以“NEXT_PUBLIC_”开头。

.env 文件

接下来,在主目录中创建一个新文件夹,并将其命名为“lib”。在此文件夹中,创建两个新文件:base.ts 和 service.ts。将以下代码复制并粘贴到 base.ts 文件中。

const API_URL = <string>process.env.NEXT_PUBLIC_WORDPRESS_API_ENDPOINT;

export async function fetchAPI(
  query = "",
  { variables }: Record<string, any> = {}
) {
  const headers = { "Content-Type": "application/json" };

  const res = await fetch(API_URL, {
    headers,
    method: "POST",
    body: JSON.stringify({
      query,
      variables,
    }),
  });

  const json = await res.json();

  if (json.errors) {
    console.error(json.errors);
    throw new Error("Failed to fetch API");
  }
  return json.data;
}
Enter fullscreen mode Exit fullscreen mode

在 base.ts 文件中,我们导出了 fetchAPI 函数,该函数用于从存储在 .env 文件中的 WordPress 端点获取数据。我们可以向其传递一个query字符串和一个variables对象,以向端点发出请求并检索所需的数据。

现在让我们继续编写查询以从 WordPress 获取所有博客文章。

在 WordPress 仪表板中,导航到 GraphQL IDE。IDE 允许我们尝试 GraphQL 查询并查看返回数据的结构。这可以帮助您了解如何构建查询并使数据与应用程序的需求保持一致。点击“查询编辑器”按钮打开编辑器。使用编辑器,您可以通过切换相关数据类型及其可用选项来创建 GraphQL 查询。要了解有关在 WPGraphQL 中创建查询的更多信息,可以参考此资源

由于我们想要获取帖子,因此以下查询用于从 WordPress 获取前几篇博客帖子:

query FetchPosts($first: Int = 10) {
  posts(first: $first) {
    nodes {
      excerpt
      featuredImage {
        node {
          sourceUrl
        }
      }
      slug
      title
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

该变量first表示每次请求要获取的帖子数量。默认值为 10。运行查询时,这就是响应的结构。

退回的帖子

继续,回到您的项目文件夹,将此代码复制并粘贴到您的 service.ts 文件中。

import { fetchAPI } from "./base";

export async function getPosts(first = 10) {
  const data = await fetchAPI(
    `query FetchPosts($first: Int = 10) {
        posts(first: $first) {
          nodes {
            excerpt
            featuredImage {
              node {
                sourceUrl
              }
            }
            slug
            title
          }
        }
      }`,
    {
      variables: {
        first,
      },
    }
  );

  return data?.posts?.nodes;
}
Enter fullscreen mode Exit fullscreen mode

看看我们如何将 FetchPosts 查询传递给 fetchAPI 函数。当 getPosts 函数被调用时,它会发出请求并获取指定数量的帖子,然后返回数据。service.ts 文件提供了一个空间,用于定义用于在 WordPress 中检索和管理数据的附加函数/服务。

我们将检索并显示主页上的帖子,主页是 pages 文件夹中的 index.tsx 文件。对于静态站点生成,我们将使用getStaticPropsgetStaticPaths函数来预渲染页面。要了解有关 Next.js 中数据获取和预渲染的更多信息,请参阅此资源

index.tsxGetStaticProps文件中,我们需要从下一个模块导入类型,因为我们使用的是 TypeScript。我们还必须getPostslib目录导入服务。

import { GetStaticProps } from "next";
import { getPosts } from "@/lib/service";
Enter fullscreen mode Exit fullscreen mode

之后,我们需要getStaticProps在 HomePage 函数下方创建一个名为的函数。在这个函数中,我们将调用getPosts服务从 WordPress 请求数据。一旦我们获得了帖子,我们就会将它们作为 prop 返回,并传递给 HomePage 函数(默认导出)。

export const getStaticProps: GetStaticProps = async () => {
  const posts = await getPosts(100); // retrieve first 100 posts

  return {
    props: {
      posts,
    },
    revalidate: 3600,
  };
};
Enter fullscreen mode Exit fullscreen mode

getStaticProps函数被调用时,它将返回一个帖子数组,该数组将作为 prop 传递给 HomePage 函数。我们可以在 HomePage 内部访问这个 prop。

返回数组中的每个帖子都是一个对象,具有titleslugexcerptfeaturingImage等属性,我们可以通过检查 WPGraphQL IDE 中每个帖子的结构来看到。

帖子结构

要在主页上显示每篇文章,我们需要映射文章数组并为每个文章创建一个 PostBlock 组件。PostBlock 组件位于components文件夹中。

我们还需要修改 PostBlock 组件,使其能够处理每个帖子的标题、slug、摘录和featuredImage 属性,并适当地显示数据。

这是更新后的index.tsx文件:

import { GetStaticProps } from "next";

import { Hero } from "@/components/Hero";
import { PostBlock } from "@/components/PostBlock";
import { getPosts } from "@/lib/service";

export default function HomePage({ posts }: { posts: any }) {
  return (
    <>
      <Hero />
      <div className="container mx-auto py-8">
        <h3 className="text-xl">All my posts (5)</h3>
        <div className="my-6 grid grid-flow-row grid-cols-1 md:grid-cols-2 lg:grid-cols-4">
          {posts.map((post: any) => {
            return <PostBlock key={post.slug} post={post} />;
          })}
        </div>
      </div>
    </>
  );
}

export const getStaticProps: GetStaticProps = async () => {
  const posts = await getPosts(100); // retrieve first 100 posts

  return {
    props: {
      posts,
    },
    revalidate: 3600,
  };
};

Enter fullscreen mode Exit fullscreen mode

为了确保 PostBlock 组件能够正确显示每篇帖子的数据,我们需要对其进行修改。您可以在components文件夹中找到 PostBlock 组件。

我们需要确保 PostBlock 组件可以访问我们传入的每个帖子的标题、摘录、slug 和 featuringImage 属性。然后,我们可以使用这些属性来适当地显示数据。

例如,我们可能希望将文章标题显示为标题,将摘录显示为简短摘要,并将精选图片显示为缩略图。我们还需要创建一个链接,当用户点击该链接时,该链接会将用户引导至完整的文章。

import Link from "next/link";
import Image from "next/image";

import defaultImage from "@/assets/images/default.jpg";

export const PostBlock = ({ post }: { post: any }) => {
  return (
    <div className="post-block p-2 rounded-md">
      <Link href={`/blog/${post.slug}`}>
        <div className="relative h-80 transition-all duration-200 ease-linear hover:-translate-y-[3px]">
          <Image
            src={post.featuredImage.node.sourceUrl ?? defaultImage}
            fill
            alt={post.title}
            className="absolute rounded-md h-full w-full object-cover"
          />
        </div>
      </Link>
      <Link href={`/blog/${post.slug}`} className="post-content my-4">
        <h3 className="text-2xl py-4">{post.title}</h3>
        <p className="italic">{post.excerpt}</p>
      </Link>
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

修改后请务必测试 PostBlock 组件,以确保数据正确显示。

对代码进行所有必要的更改后,您可以通过npm run dev在终端中运行以下命令来启动开发服务器。请确保您的 WordPress 本地服务器仍在运行。Next.js 通常会在端口 3000 上启动服务器,因此请在浏览器中访问http://localhost:3000来查看网站。如果一切正常,您应该会看到网站的主页,但屏幕上会显示类似以下的错误信息:

图像错误

此错误与 Next.js 中 next/image 组件的使用有关。错误消息表明,next/image 组件的 src 属性指向的图片文件,其 URL 包含the-headless-blog.localnext/image 配置不允许的主机名。

如果您想使用 Next.js 项目以外的来源的图片,则需要正确配置 next.config.js 文件。这包括创建允许加载图片的域名列表。此安全措施旨在防止跨站点脚本 (XSS) 攻击。

因此,为了修复您看到的错误,您可以将the-headless-blog.local主机名添加到 next.config.js 文件中允许的域名列表中。这样您就可以从 WordPress 服务器加载图片了。点击此处了解更多信息。

next.config.js

修改代码后,需要重启开发服务器才能使更改生效。为此,请Ctrl + C在终端中按下 来停止当前的开发服务器实例。

然后,npm run dev再次运行该命令,使用更新后的代码启动开发服务器。这应该可以确保你的更改已正确传播并在浏览器中可见。

检索到的帖子

恭喜您成功从 WordPress 服务器检索帖子!🎉🎉🎉

但是,我们还需要对 PostBlock 组件进行一项修改。WordPress 返回的摘录是一个 HTML 段落,因此我们需要进行一些调整以确保它能够正确显示。

为此,我们可以将pPostBlock 组件中的标签更改为 adiv标签,并使用dangerlySetInnerHTML属性将摘录显示为 HTML。这将确保摘录正确显示,并且摘录中的所有 HTML 标签都能正确呈现。

以下是 PostBlock 组件的更新代码:

import Link from "next/link";
import Image from "next/image";

import defaultImage from "@/assets/images/default.jpg";

export const PostBlock = ({ post }: { post: any }) => {
  return (
    <div className="post-block p-2 rounded-md">
      <Link href={`/blog/${post.slug}`}>
        <div className="relative h-80 transition-all duration-200 ease-linear hover:-translate-y-[3px]">
          <Image
            src={post.featuredImage.node.sourceUrl ?? defaultImage}
            fill
            alt={post.title}
            className="absolute rounded-md h-full w-full object-cover"
          />
        </div>
      </Link>
      <Link href={`/blog/${post.slug}`} className="post-content my-4">
        <h3 className="text-2xl py-4">{post.title}</h3>
        <div
          className="italic"
          dangerouslySetInnerHTML={{ __html: post.excerpt }}
        ></div>
      </Link>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

保存更改后,我们的帖子应该可以正确呈现。

帖子

为了在主页上显示正确的帖子数量,我们需要修改 HomePage 函数来访问数组length的属性posts

帖子长度
帖子长度


目前,点击首页上的任何帖子都会跳转到 404 页面。为了解决这个问题,我们需要为帖子详情页面建立动态路由。

为此,我们可以posts在 pages 文件夹中创建一个名为 的新文件夹。在 posts 文件夹中,我们可以创建一个名为 的新文件[slug].tsx。这将是用于呈现每篇帖子详细信息的模板。

创建 [slug].tsx 文件后,我们可以将 PostBlock 组件中的链接结构从“blog/${post.slug}”更新为“posts/${post.slug}”,以匹配我们刚刚创建的动态路由。这将确保点击主页上的帖子会跳转到正确的帖子详情页面。

更新了链接结构

接下来,为了通过 slug 获取单篇文章,我们可以在lib文件夹下的service.ts文件中创建并导出一个新服务。以下是我们可以用来通过 slug 获取单篇文章的查询:

query GetPost($id: ID = "") {
  post(id: $id, idType: SLUG) {
    content
    featuredImage {
      node {
        sourceUrl
      }
    }
    slug
    title
  }
}
Enter fullscreen mode Exit fullscreen mode

下面是通过 slug 获取单个帖子的服务:

export async function getPostBySlug(slug: string) {
  const data = await fetchAPI(
    `query GetPost($id: ID = "") {
    post(id: $id, idType: SLUG) {
      content
      featuredImage {
        node {
          sourceUrl
        }
      }
      slug
      title
    }
  }`,
    {
      variables: {
        id: slug,
      },
    }
  );

  return data?.post;
}
Enter fullscreen mode Exit fullscreen mode

我们将在 [slug].tsx 文件中的函数内部调用 getPostBySlug 函数getStaticProps。此函数将返回帖子数据,然后我们会将其作为 prop 传递给页面组件进行渲染。您可以将下面提供的代码复制并粘贴到 [slug].tsx 文件中,并在其后找到代码说明。

import { GetStaticProps } from "next";
import { GetStaticPaths } from "next";

import { getPosts, getPostBySlug } from "@/lib/service";

export default function PostDetails({ post }: { post: any }) {
  return (
    <section className="container mx-auto py-12">
      <div
        className="post-header relative flex flex-col items-center justify-center w-full min-h-[200px] rounded-md"
        style={{
          backgroundImage: `url(${post.featuredImage.node.sourceUrl})`,
          backgroundSize: "cover",
          backgroundPosition: "center",
        }}
      >
        <div
          className="absolute w-full h-full z-10"
          style={{ backgroundColor: "rgba(0, 0, 0, .5)" }}
        ></div>
        <div className="z-20 text-center">
          <h1 className="text-2xl md:text-4xl mb-4">{post.title}</h1>
          <p className="italic">By Jeffrey</p>
        </div>
      </div>
      <div
        className="post-content w-full md:w-3/5 mx-auto mt-20 py-6 text-lg"
        dangerouslySetInnerHTML={{ __html: post.content }}
      ></div>
    </section>
  );
}

export const getStaticPaths: GetStaticPaths = async () => {
  const posts = await getPosts(100); // retrieve first 100 posts

  return {
    paths: posts.map((post: any) => `/posts/${post.slug}`),
    fallback: false,
  };
};

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const post = await getPostBySlug(params?.slug as string);

  return {
    props: { post },
  };
};

Enter fullscreen mode Exit fullscreen mode

PostDetails 函数是用于渲染帖子页面的组件。它接收一个 post 对象作为 prop,其中包含待渲染帖子的信息。该函数会渲染帖子的 header 部分,其中包含帖子的特色图片、标题和作者。我们还会在 header 下方渲染帖子的内容。

在 Next.js 中,如果页面包含动态路由并使用getStaticProps,则需要定义一个要静态生成的路径列表。Next.js 会在构建时为每条路由(每篇文章)生成必要的页面。这意味着,当用户访问我们的一篇文章时,他们将看到页面的预渲染版本,而无需等待页面在客户端加载和渲染。在本例中,它使用getPostsservice.ts 文件中的 函数检索前 100 篇文章,并将它们映射到一个与每篇文章的 slug 对应的路径数组。fallback属性设置为 false,这意味着如果用户导航到不存在的文章,Next.js 将返回 404 页面。

getStaticProps函数之前已在 index.tsx 文件中使用过,但在本例中,请注意参数slug是通过解构传递params给函数的对象获得的。我们使用 slug 是因为它对应于我们的文件名 [slug].tsx,并且用方括号括起来。您可以在此处了解有关 Next.js 路由的更多信息。

保存所有更改后,单击主页中的某个帖子将带您进入浏览器中相应的帖子详细信息页面。

帖子详情

部署我们的博客

是时候与世界分享我们的成果了!🎉 要让使用 WordPress + Next.js 组合的网站或博客上线,我们首先需要为 WordPress 后端搭建一个在线服务器,然后在Vercel或任何其他静态托管服务提供商上部署 Next.js 前端。

重要提示:通常,您需要获取一个域名,例如 example.com,并将其指向部署在 Vercel 上的前端。然后,您可以为 WordPress 后端创建一个子域名,例如 api.example.com。这样,您可以将主域名用于网站,而子域名则用作网站后端的服务器。

但在我们的例子中,我们不会为项目创建域名或子域名。相反,我们将使用名为000webhost的免费托管服务来托管我们的 WordPress 后端,然后在 Vercel 上部署我们的前端。

部署我们的 WordPress 后端。

  1. 前往https://www.000webhost.com/并创建一个新帐户。别忘了验证你的电子邮件地址,而且最棒的是,它是免费的!
  2. 登录并导航至https://www.000webhost.com/members/website/list。点击“创建新网站”按钮,并在模态表单中输入网站名称和密码。最后,点击“创建”按钮,完成后您将被重定向到仪表板。创建网站
  3. 下一步是安装 WordPress。在控制面板中,点击“WordPress”卡片,然后在屏幕上的表单中输入您想要的管理员用户名和密码。填写完成后,点击“安装”按钮,等待 WordPress 安装完成。主机仪表板 设置 WordPress 安装的凭据 WordPress 安装
  4. 安装完成后,点击“前往配置页面”按钮,系统将提示您登录。输入您在上一步中创建的管理员用户名和密码。如果您遇到 404 页面或被重定向到网站列表页面,请重试步骤 3。WordPress 仪表板
  5. 在 WordPress 仪表板上,我们需要下载并配置插件,并像本文前面一样创建一些文章。但是,如果您想将本地 WordPress 安装迁移到现有 WordPress,则可以轻松使用名为“一体式 WP 迁移”的插件。您可以在此处了解有关使用该插件进行迁移的更多信息。由于我们的本地 WordPress 安装中内容不多,因此只需重复此过程即可。

在 Vercel 上部署我们的前端

在继续操作之前,请确保您已创建GitHub帐户,并且具备 Git 知识。如果您不了解 Git,可以点击此处了解更多信息。

接下来,打开工作文件夹中的next.config.js文件,并在域数组中添加实时 WordPress 主机名的新域。api-headless-blog.000webhostapp.com
添加新主机名

  1. 在你的 GitHub 帐户上为你的前端创建一个新的仓库。你可以将其命名为“nextjs-headless-wordpress”。
  2. 在您的工作文件夹中,在终端中依次运行以下命令来初始化 Git 并推送您的代码:

    git init
    git commit -m "first commit"
    git branch -M main
    git remote add origin <your git repo url>
    git push -u origin main
    
  3. 将代码推送到main分支后,转到https://vercel.com并使用您的 GitHub 帐户登录。在仪表板上,添加一个新项目,然后单击刚刚创建的存储库旁边的“导入”按钮。

    新项目

  4. 在项目配置页面的“环境变量”部分中,像在本地一样输入 WordPress API 端点,但使用实时 WordPress GraphQL 端点。然后点击“添加”按钮。NEXT_PUBLIC_WORDPRESS_API_ENDPOINT = <live endpoint>

    环境变量

  5. 点击“部署”按钮开始部署过程。

如果一切顺利,你的项目现在应该可以顺利部署了!如果遇到任何问题,请仔细检查你的步骤并重试。

现在,激动人心的时刻到了——你可以和朋友们分享你新创建的博客了!这是我的链接:https://nextjs-headless-wordpress-lac.vercel.app/

优化博客的SEO

搜索引擎优化

如果本文对您有帮助,请在Twitter上关注我。

在 Twitter 的 Space 上,一位开发者表示担心 Next.js 和 React 不适合用来搭建博客,因为 SEO 优化比较困难。然而,到了 2023 年,网站或博客的 SEO 优化已经相当容易实现了。

在本节中,我们将介绍以下内容:

  • 创建自定义 SEO 组件
  • 生成站点地图
  • Google 网站所有权验证

创建自定义 SEO 组件

我们将实现一个自定义 SEO 组件,该组件可以通过生成元标记和其他 HTML 标记来增强我们博客的搜索引擎优化 (SEO)。该组件将接受多个属性,包括页面标题、描述、图片和类型,以便创建相关的元标记,方便搜索引擎索引和社交媒体分享。此外,它还将整合指向不同图标(例如网站图标)的链接,并设置规范 URL 以避免重复问题。使用此组件将确保我们的博客拥有优化的元标记,从而提高搜索引擎排名,并增强用户在社交媒体平台上分享网站的体验。

步骤 1
在 .env 文件中 添加一个名为 的新环境变量NEXT_PUBLIC_ROOT_URL,其值设置为我们博客的根 URL。由于我们目前处于开发阶段,因此根 URL 应为http://localhost:3000

.env 文件

第 2 步

使用像Favicon.io这样的在线生成器为您的博客创建网站图标。这些图标将在即将推出的 SEO 组件中使用。为了实现最佳优化,建议生成 5 种类型的图标,包括:

  • faviconIco:这是博客/网站的 favicon 图标,出现在浏览器选项卡和书签中。
  • favicon180:当用户将网站添加到主屏幕时,此图标用于 Apple 设备。
  • favicon32:这是另一个 favicon 图标,但尺寸为 32x32 像素。
  • favicon16:这个 favicon 图标更小,尺寸为 16x16 像素。
  • maskIcon:这是一个特殊的图标,用作 Safari 浏览器中固定标签图标的蒙版。

但是,我不会为这个项目生成 maskIcon。

使用在线生成器生成网站图标后,将下载一个包含图标的 zip 文件。或者,您也可以按照自己喜欢的方式自行创建这些图标。

在assets文件夹中,为图标创建一个新文件夹。您可以将其命名为“favicons”,并将下载的图标复制到该文件夹​​中。

Favicons文件夹

在组件文件夹中,创建一个新文件夹并将其命名为“SEO”。在该文件夹中,创建一个 index.tsx 文件,用于保存组件的代码。将以下代码复制并粘贴到您的文件中。

import Head from "next/head";
import { useRouter } from "next/router";

import faviconIco from "@/assets/favicons/favicon.ico";
import appleTouchIcon from "@/assets/favicons/apple-touch-icon.png";
import favicon32 from "@/assets/favicons/favicon-32x32.png";
import favicon16 from "@/assets/favicons/favicon-16x16.png";
import defaultImage from "@/assets/images/default.jpg";

interface SEOProps {
  title: string;
  description?: string;
  image?: string;
  type?: "website" | "article";
}

const pageImage = process.env.NEXT_PUBLIC_ROOT_URL + defaultImage.src.slice(1);

const ROOT_URL = process.env.NEXT_PUBLIC_ROOT_URL as string;

export const SEO = ({
  title,
  description,
  image = pageImage,
  type = "website",
}: SEOProps) => {
  const router = useRouter();
  const url = `${ROOT_URL}/${router.asPath}`;

  return (
    <Head>
      <title>{title}</title>
      <meta charSet="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <meta content="IE=edge" httpEquiv="X-UA-Compatible" />
      <meta name="description" content={description} />
      <meta name="robots" content="follow, index" />

      <meta name="twitter:card" content="summary_large_image" />
      <meta name="twitter:site" content="@JeffreySunny1" />
      <meta name="twitter:image" content={image} />
      <meta name="twitter:title" content={title} />
      <meta name="twitter:description" content={description} />

      <meta property="og:site_name" content="Jeffrey's Blog" />
      <meta property="og:title" content={title} />
      <meta property="og:description" content={description} />
      <meta property="og:url" content={url} />
      <meta property="og:type" content={type} />
      <meta property="og:image" content={image} />

      <link rel="shortcut icon" href={faviconIco.src} />
      <link rel="apple-touch-icon" sizes="180x180" href={appleTouchIcon.src} />
      <link rel="icon" type="image/png" sizes="32x32" href={favicon32.src} />
      <link rel="icon" type="image/png" sizes="16x16" href={favicon16.src} />
      {/* <link rel="mask-icon" href="" color="#5bbad5" /> Add mask icon */}
      <meta name="msapplication-TileColor" content="#da532c" />
      <meta name="theme-color" content="#ffffff" />

      <link rel="canonical" href={url} />
    </Head>
  );
};
Enter fullscreen mode Exit fullscreen mode

该组件会生成元标签和其他 HTML 标记,以提升我们博客的搜索引擎优化 (SEO)。它需要四个属性——标题、描述、图片和类型——来生成合适的元标签,用于社交媒体分享和搜索引擎索引。我添加了各种元标签,包括 Twitter 和 Open Graph 的元标签,以及用于不同大小的图标的链接标签。此外,还设置了规范链接,以确保搜索引擎索引正确的 URL 并避免重复。

让我们修改 pages/index.tsx 和 posts/[slug].tsx 文件以使用新的 SEO 组件。

页面/索引.tsx

export default function HomePage({ posts }: { posts: any }) {
  return (
    <>
      <SEO
        title="Welcome to Jeffrey's Blog"
        description="Access all tech content and beyond"
      />
      <Hero />
      <div className="container mx-auto py-8">
        <h3 className="text-xl">All my posts ({posts.length})</h3>
        <div className="my-6 grid grid-flow-row grid-cols-1 md:grid-cols-2 lg:grid-cols-4">
          {posts.map((post: any) => {
            return <PostBlock key={post.slug} post={post} />;
          })}
        </div>
      </div>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

结果如下:

搜索引擎优化

帖子/[slug].tsx

export default function PostDetails({ post }: { post: any }) {
  return (
    <>
      <SEO
        title={`${post.title} - Posts`}
        description={post.excerpt}
        image={post.featuredImage.node.sourceUrl}
        type="article"
      />
      <section className="container mx-auto py-12">
        <div
          className="post-header relative flex flex-col items-center justify-center w-full min-h-[200px] rounded-md"
          style={{
            backgroundImage: `url(${post.featuredImage.node.sourceUrl})`,
            backgroundSize: "cover",
            backgroundPosition: "center",
          }}
        >
          <div
            className="absolute w-full h-full z-10"
            style={{ backgroundColor: "rgba(0, 0, 0, .5)" }}
          ></div>
          <div className="z-20 text-center">
            <h1 className="text-2xl md:text-4xl mb-4">{post.title}</h1>
            <p className="italic">By Jeffrey</p>
          </div>
        </div>
        <div
          className="post-content w-full md:w-3/5 mx-auto mt-20 py-6 text-lg"
          dangerouslySetInnerHTML={{ __html: post.content }}
        ></div>
      </section>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

在帖子详情页面,帖子的标题、摘录和精选图片会被传递给 SEO 组件。页面的类型设置为“article”,以指示其所代表的内容类型。如果您使用开发者工具检查 head 元素,您将看到我们添加的所有 SEO 标签,这些标签对于优化页面的搜索引擎排名至关重要。

开发人员工具

生成站点地图

我们为什么要生成站点地图?

站点地图可帮助 Google 等搜索引擎更有效地抓取和索引网站,使用户更轻松地发现网站上的内容,并且可以将其提交给搜索引擎,作为网站搜索引擎优化 (SEO) 策略的一部分。

要为我们的博客生成站点地图,

要安装 Next.js 的站点地图生成器包,请运行 npm install next-sitemap。然后在根目录中创建一个名为 next-sitemap.config.js 的基本配置文件,并在其中添加以下代码:

/** @type {import('next-sitemap').IConfig} */
module.exports = {
  siteUrl: process.env.NEXT_PUBLIC_ROOT_URL,
  generateRobotsTxt: true
};
Enter fullscreen mode Exit fullscreen mode

确保使用指向根 URL 的正确环境变量。

如果您的根 URL 环境变量与此不同,请确保使用正确的环境变量。然后,在 package.json 中添加一个值为“next-sitemap”的“postbuild”脚本。此脚本将在“build”脚本运行后立即为我们的博客生成站点地图。
构建后 Package.json

在终端上运行该npm run build命令,然后启动开发服务器。您的博客站点地图应该已经生成,您可以通过以下链接访问:http://localhost:3000/sitemap-0.xml
生成的站点地图
生成的站点地图

Google 网站所有权验证

搜索引擎优化 (SEO) 的一个关键部分是验证您的域名/网站的所有权,向 Google 验证您的域名或网站(在本例中为我们的博客)有多种好处,包括:

  • 您的网站编入索引:Google 使用您的网站所有权验证来确认您是网站的所有者,这有助于确保您的网站在 Google 搜索结果中被正确编入索引。
  • 安全性:它有助于防止未经授权访问您的网站,并确保您可以控制您的网站在 Google 搜索中的存在。
  • SEO:通过访问 Google Search Console,您可以监控您的网站或博客在 Google 搜索结果中的表现,并找出改进搜索引擎优化 (SEO) 效果的机会。

要在 Google 上验证您的博客所有权,请按以下步骤操作:

  1. 登录您的 Google 帐户并访问Google Search Console
  2. 点击“添加资源”,并输入您博客的首页网址,该网址应为您博客的实际链接(例如https://nextjs-headless-wordpress-lac.vercel.app/)。出现提示时,选择合适的资源类型。Google 搜索控制台
  3. 如果您有自定义域名,请选择“域名”选项卡并输入您的域名。否则,请选择“URL 前缀”选项卡并点击“继续”。
  4. 选择“HTML 标签”验证方法并复制提供的元标签。请勿关闭模态框或点击任何内容。
  5. 打开 _components_folder 中的 SEO 组件文件,并将元标记代码粘贴到 Head 标记内,如下所示:

站点所有权验证

重要提示:您需要将NEXT_PUBLIC_ROOT_URL环境变量添加到 Vercel 项目的项目设置中。此变量应设置为您博客的实际 URL,例如https://nextjs-headless-wordpress-lac.vercel.app。别忘了点击“保存”按钮。
更新的环境变量

将更新后的代码推送到 GitHub 后,我们就可以重新部署博客了。请按顺序执行以下命令:

git add .
git commit -m "sitemap generation and adjustment"
git push origin main
Enter fullscreen mode Exit fullscreen mode

我们的 Vercel 设置配置为监视主分支上所做的更改,并在检测到更新后自动重新部署博客。

部署成功后,返回 Google Search Console 页面,然后点击“验证”按钮。如果元标记已正确添加,屏幕上将显示“所有权已验证”消息。
图片描述

此外,您还需要将站点地图添加到 Google Search Console。在侧边栏上,点击“站点地图”链接。在“添加新站点地图”框中,输入“sitemap.xml”(即我们的站点地图所在的位置,网址为https://nextjs-headless-wordpress-lac.vercel.app/sitemap.xml),然后点击“提交”。

恭喜!您的博客现已完成 SEO 优化,可供搜索引擎抓取,但站点地图的完全传播可能需要一些时间。


概括

谢谢大家一直看到这里😎。我想强调的是,这份全面的指南不仅限于博客。它还可以用于开发强大的 Web 应用程序,例如电商网站、房地产列表、在线目录等等。通过使用 Advanced Custom Fields 和 WooCommerce 等插件,您可以根据应用程序的需求创建自定义字段和布局。借助身份验证和授权功能,WordPress 可以作为您的后端,而 Next.js 则负责处理您的前端,从而打造一个响应迅速且经济高效的网站。

感谢您的关注。如果您觉得本指南对您有帮助,欢迎在Twitter上关注我。

欢迎在下面的评论区留下你的评论、想法和问题。我很乐意回复!

图片来源:https://freepik.com,https : //canva.com

文章来源:https://dev.to/jeffsalive/a-detailed-guide-on-how-to-build-a-website-with-nextjs-and-headless-wordpress-seo-2023-web-development-4nof
PREV
如何伪装成一名软件工程师
NEXT
JavaScript 中节流最简单的解释✨🚀