”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 使用 JSON-LD 提升博客的 SEO:我如何使用结构化数据添加丰富的结果

使用 JSON-LD 提升博客的 SEO:我如何使用结构化数据添加丰富的结果

发布于2024-11-07
浏览:329

Boost Your Blog’s SEO with JSON-LD: How I Added Rich Results Using Structured Data

Introduction

A few years ago in 2022, I attended SCaLE 19x. For those who are not aware, SCaLE is an acronym which stands for Southern California Linux Expo and is the name of a community-run open-source and free software conference held annually in the greater Los Angeles area.

Among the many talks given, one I attended was titledEnrich Your Enterprise Knowledge Graph with Linked Open Data via JSON-LDand presented by an individual named Jans Aasman. The talk was quite informative and broadly covered how linked open data was used and growing. Linked open data started in the semantic web community many years ago and is a tool which can be used for making web pages understandable by machines.

Subsequently, one interesting thing I learned about from the talk was how linked data could be used to enable developments in artificial intelligence since it can help make documents more understandable for machines. Given the recent advances in AI, the talk served as a good primer, sparking my interest in that area.

Unfortunately, I wasn’t aware of any practical applications for the information at the time. The talk ended with a note that Google uses JSON-LD (JavaScript Object Notation for Linked Data) for product descriptions, but that didn't resonate with me since I wasn't working on anything having to do with search at the time. Since then, I've started a blog and returned to this technology after gaining an interest in search engine optimization.

Understanding JSON-LD

What is JSON-LD? Here's a quote from Wikipedia's JSON-LD definition:

JSON-LD (JavaScript Object Notation for Linked Data) is a method of encoding linked data using JSON.

From what I understand, linked data allows the linking of data entities to each other. For example, one could define a person entity and have it linked to an article entity where the article has an author. One way to make use of JSON-LD is for SEO purposes using type definitions from https://schema.org.

As an example, here is what an ImageObject instance would look like:

{
  "@context": "https://schema.org",
  "@type": "ImageObject",
  "contentUrl": "https://logarithmicspirals.com/some-image.png"
}

From what I remember of Jans Aasman's talk at SCaLE, linked data can be used to buildknowledge graphs for both public and private use. JSON-LD is a tool to make accessing this data very simple by leveraging the simplicity and support of JSON across many programming languages. In the case of this article, JSON-LD helps contribute toGoogle's knowledge graph by providing structured data about the article.

When I first attended the talk, I wasn't working on any projects which could readily benefit from structured data or JSON-LD. However, after starting this blog I came back around to the technology after exploring the Google Search Console. Google and other search engines support certain schemas for enhancing search results. Google provides documentation about this in an article titledStructured data markup that Google Search supports.

Implementing JSON-LD for Rich Results

The first step of implementing JSON-LD for rich results was to connect the structured data markup supported by Google with the content I offer on my blog. Features like carousels for restaurant reviews aren't really something I can make use. That said, I could definitely use breadcrumb, article, and image markup.

As such, I decided to start with article markup. The article markup ended up being the most involved and least rewarding of the three. In this case, rewarding means it shows up in Google Search Console under the enhancements tab.

To start creating the JSON-LD, I looked for a TypeScript package I could install to help. Thankfully, I was able to find the package schema-dts which allows developers to create objects matching schemas from https://schema.org.

After installing the package with npm install schema-dts, I got to work on some refactoring to make it easy to add schemas to various pages.

Blog Post Article Markup

The first thing I did was create a file src/utils/get-schema.ts. In that file, I added the following code:

import type { CollectionEntry } from "astro:content";
import type { BlogPosting, WithContext, Person } from "schema-dts";

const defaultCreatorName = "Logarithmic Spirals";
const defaultCreator: Person = {
  "@type": "Person",
  "name": defaultCreatorName,
  "url": "https://logarithmicspirals.com/about/"
};

const getBlogPostingSchema = (post: CollectionEntry, url: string): WithContext => {
  const { title, description, tags, pubDate, updatedDate, heroImage } = post.data;
  const image = heroImage.src;

  return {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "headline": title,
    "description": description,
    "keywords": tags,
    "author": defaultCreator,
    "datePublished": pubDate.toISOString(),
    ...(updatedDate && { "dateModified": updatedDate.toISOString() }),
    "image": image,
    "inLanguage": "en-US",
    "url": url
  };
};

export { getBlogPostingSchema }

The code uses the frontmatter schema I defined when I originally created the site (although it has been modified over time). Note that this code is partially influenced by code from an article titledAdding structured data to blog posts using Astro.

The getBlogPostingSchema can then be used to render the blog post pages using the blog post data.

Next, I had to update the code for my layouts to add the schema to the various pages it needs to be on. To do this, I had to update my base page layout. The base page layout is a custom layout I have defined atsrc/layouts/BasePage.astro. Here's what that looks like:

---
import type { WithContext, Thing, WebPage, WebSite, BreadcrumbList } from "schema-dts";
import BaseHead from "@components/BaseHead.astro";
import Body from "@layouts/Body.astro";

interface Props {
  title: string;
  description: string;
  image?: string;
  hasNavBar?: boolean;
  schema?: Thing;
  breadcrumb?: BreadcrumbList[] | BreadcrumbList;
}

const { title, description, image, hasNavBar, schema, breadcrumb } = Astro.props;

const webSiteSchema: WithContext = {
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "Logarithmic Spirals",
  "url": Astro.site?.toString()
};
const webPageSchema: WithContext = {
  "@context": "https://schema.org",
  "@type": "WebPage",
  "url": new URL(Astro.url.pathname, Astro.site)   "/",
  "description": description,
  "isPartOf": webSiteSchema
};

if (breadcrumb) {
  webPageSchema.breadcrumb = breadcrumb;
}

let schemaToUse: Thing = webPageSchema;

if (schema) {
  schema["isPartOf"] = webPageSchema;
  schemaToUse = schema;
}
---



  
    
    
  
  
    
  


Note the separation of schema and breadcrumb. I treat those separately since not every page with a schema has a breadcrumb. The most important piece is the injection of the JSON-LD into the page through a script tag in the head of the document.

The article schema then gets passed in through child pages like this:

---
// ...
const schema: BlogPosting = getBlogPostingSchema(
  post,
  new URL(Astro.url.pathname, Astro.site).toString()   "/",
);
---



Breadcrumb Markup

For a while now, my pages have already had breadcrumb navigation elements on the individual blog post and tag pages. However, it looks like Google doesn't quite understand the HTML breadcrumb as well as it does the JSON-LD breadcrumb (note that by HTML I mean plain HTML without embedded structured data).

After adding the breadcrumb markup, I've seen links to my site have changed in Google. Where I once saw trails likehttps://logarithmicspirals.com > blog > website-migration-aws-amplify-to-cloudflare-insights, I now seehttps://logarithmicspirals.com > Blog. While a subtle difference, it shows that Google is paying attention to the newly added structured data.

To implement the breadcrumbs, I first added a new function to src/utils/get-schema.ts:

const getBlogPostBreadcrumbListSchema = (title: string, site?: URL): WithContext => {
  return {
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    itemListElement: [
      {
        "@type": "ListItem",
        position: 1,
        name: "Home",
        item: site?.toString(),
      },
      {
        "@type": "ListItem",
        position: 2,
        name: "Blog",
        item: new URL("blog", site)   "/",
      },
      {
        "@type": "ListItem",
        position: 3,
        name: title,
      },
    ],
  };
};

The output of this function creates JSON-LD matching the examples given by Google inBreadcrumb (BreadcrumbList) structured dataand is intended to be used on pages matching this path scheme https://logarithmicspirals.com/blog/{slug}.

Image Markup

Lastly, another opportunity I saw to make use of Rich Results was on the /gallery/ page of my website. To achieve this, I created the following functions in src/utils/get-schema.ts:

const getImageObjectSchema = (imageNode: ImageNode): WithContext => {
  return {
    "@context": "https://schema.org",
    "@type": "ImageObject",
    "contentUrl": imageNode.url,
    "creator": defaultCreator,
    "creditText": defaultCreatorName,
    "copyrightNotice": defaultCreatorName
  };
};

const getImageGallerySchema = (imageNodes: Array): WithContext => {
  return {
    "@context": "https://schema.org",
    "@type": "ImageGallery",
    "image": imageNodes.map(imageNode => getImageObjectSchema(imageNode))
  };
};

The ImageNode type is a custom type I created and looks like this:

export type ImageNode = {
  key: string,
  title: string,
  technical: {
    bodyMake: string,
    bodyModel: string,
    focalLength: string,
    iso: string,
    lensMake: string,
    lensModel: string
  },
  url: string,
  nodeIndex?: number
};

For some better understanding of the ImageNode type, check out this previous article I wrote:Photo Gallery Migration: Gatsby to Astro Follow-Up.

The schema generation is then used like this:

---
// Import the IMAGES constant which is an Array of ImageNodes.
// ...
const schema = getImageGallerySchema(IMAGES);
---



Results and Google Search Console Enhancements

So far, I haven't seen a noticeable increase in traffic through Google Search, but to be fair, my blog is quite niche, and the changes haven't been live for long.

In terms of search appearance, the breadcrumbs are showing up and I've yet to check on the results for the image markup.

The most notable change has been in the Google Search Console where I'm now seeing an Enhancements section with information about the breadcrumbs and images.

Boost Your Blog’s SEO with JSON-LD: How I Added Rich Results Using Structured Data

Additionally, Google also offers the Rich Results Test which allows one to test if their markup is valid for Rich Results. This tool was quite useful while I was developing the update locally since it allows one to paste the code directly in.

Conclusion

For a small project, JSON-LD may or may not offer any benefits. In the case of my blog, it made sense to try and incorporate some into pages since it helps improve the way Google understands the content of the pages. Additionally, my blog is a tech blog, so taking the time to explore this technology offered an additional benefit of giving me something to write about. However, not every blog might benefit from incorporating it like mine.

Regardless, I think this is something other developers should consider exploring since it has a rich history and some practical applications in the web development space. For example, someone working on an eCommerce site may find rich results on Google lead to more customer engagement through organic search.

Moving forward, I want to try to find some other opportunities for improving the use of structured data on my website. One thing I would like to do is add markup for the images on blog posts. I could also explore markup for videos if I ever get around to trying my hand at making video content.

版本声明 本文转载于:https://dev.to/logarithmicspirals/boost-your-blogs-seo-with-json-ld-how-i-added-rich-results-using-structured-data-nob?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 在Java中使用for-to-loop和迭代器进行收集遍历之间是否存在性能差异?
    在Java中使用for-to-loop和迭代器进行收集遍历之间是否存在性能差异?
    For Each Loop vs. Iterator: Efficiency in Collection TraversalIntroductionWhen traversing a collection in Java, the choice arises between using a for-...
    编程 发布于2025-07-18
  • 如何从PHP中的Unicode字符串中有效地产生对URL友好的sl。
    如何从PHP中的Unicode字符串中有效地产生对URL友好的sl。
    为有效的slug生成首先,该函数用指定的分隔符替换所有非字母或数字字符。此步骤可确保slug遵守URL惯例。随后,它采用ICONV函数将文本简化为us-ascii兼容格式,从而允许更广泛的字符集合兼容性。接下来,该函数使用正则表达式删除了不需要的字符,例如特殊字符和空格。此步骤可确保slug仅包含...
    编程 发布于2025-07-18
  • 如何修复\“常规错误:2006 MySQL Server在插入数据时已经消失\”?
    如何修复\“常规错误:2006 MySQL Server在插入数据时已经消失\”?
    How to Resolve "General error: 2006 MySQL server has gone away" While Inserting RecordsIntroduction:Inserting data into a MySQL database can...
    编程 发布于2025-07-18
  • PHP阵列键值异常:了解07和08的好奇情况
    PHP阵列键值异常:了解07和08的好奇情况
    PHP数组键值问题,使用07&08 在给定数月的数组中,键值07和08呈现令人困惑的行为时,就会出现一个不寻常的问题。运行print_r($月)返回意外结果:键“ 07”丢失,而键“ 08”分配给了9月的值。此问题源于PHP对领先零的解释。当一个数字带有0(例如07或08)的前缀时,PHP将其...
    编程 发布于2025-07-18
  • 如何从PHP中的数组中提取随机元素?
    如何从PHP中的数组中提取随机元素?
    从阵列中的随机选择,可以轻松从数组中获取随机项目。考虑以下数组:; 从此数组中检索一个随机项目,利用array_rand( array_rand()函数从数组返回一个随机键。通过将$项目数组索引使用此键,我们可以从数组中访问一个随机元素。这种方法为选择随机项目提供了一种直接且可靠的方法。
    编程 发布于2025-07-18
  • 您如何在Laravel Blade模板中定义变量?
    您如何在Laravel Blade模板中定义变量?
    在Laravel Blade模板中使用Elegance 在blade模板中如何分配变量对于存储以后使用的数据至关重要。在使用“ {{}}”分配变量的同时,它可能并不总是最优雅的解决方案。幸运的是,Blade通过@php Directive提供了更优雅的方法: $ old_section =“...
    编程 发布于2025-07-18
  • 在Ubuntu/linux上安装mysql-python时,如何修复\“ mysql_config \”错误?
    在Ubuntu/linux上安装mysql-python时,如何修复\“ mysql_config \”错误?
    mysql-python安装错误:“ mysql_config找不到”“ 由于缺少MySQL开发库而出现此错误。解决此问题,建议在Ubuntu上使用该分发的存储库。使用以下命令安装Python-MysqldB: sudo apt-get安装python-mysqldb sudo pip in...
    编程 发布于2025-07-18
  • 如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    Transform Pandas DataFrame Column to DateTime FormatScenario:Data within a Pandas DataFrame often exists in various formats, including strings.使用时间数据时...
    编程 发布于2025-07-18
  • 反射动态实现Go接口用于RPC方法探索
    反射动态实现Go接口用于RPC方法探索
    在GO 使用反射来实现定义RPC式方法的界面。例如,考虑一个接口,例如:键入myService接口{ 登录(用户名,密码字符串)(sessionId int,错误错误) helloworld(sessionid int)(hi String,错误错误) } 替代方案而不是依靠反射...
    编程 发布于2025-07-18
  • 如何在GO编译器中自定义编译优化?
    如何在GO编译器中自定义编译优化?
    在GO编译器中自定义编译优化 GO中的默认编译过程遵循特定的优化策略。 However, users may need to adjust these optimizations for specific requirements.Optimization Control in Go Compi...
    编程 发布于2025-07-18
  • 解决Spring Security 4.1及以上版本CORS问题指南
    解决Spring Security 4.1及以上版本CORS问题指南
    弹簧安全性cors filter:故障排除常见问题 在将Spring Security集成到现有项目中时,您可能会遇到与CORS相关的错误,如果像“访问Control-allo-allow-Origin”之类的标头,则无法设置在响应中。为了解决此问题,您可以实现自定义过滤器,例如代码段中的MyFi...
    编程 发布于2025-07-18
  • 如何使用PHP将斑点(图像)正确插入MySQL?
    如何使用PHP将斑点(图像)正确插入MySQL?
    essue VALUES('$this->image_id','file_get_contents($tmp_image)')";This code builds a string in PHP, but the function call ...
    编程 发布于2025-07-18
  • Java的Map.Entry和SimpleEntry如何简化键值对管理?
    Java的Map.Entry和SimpleEntry如何简化键值对管理?
    A Comprehensive Collection for Value Pairs: Introducing Java's Map.Entry and SimpleEntryIn Java, when defining a collection where each element com...
    编程 发布于2025-07-18
  • Spark DataFrame添加常量列的妙招
    Spark DataFrame添加常量列的妙招
    在Spark Dataframe ,将常数列添加到Spark DataFrame,该列具有适用于所有行的任意值的Spark DataFrame,可以通过多种方式实现。使用文字值(SPARK 1.3)在尝试提供直接值时,用于此问题时,旨在为此目的的column方法可能会导致错误。 df.withCo...
    编程 发布于2025-07-18
  • 我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    将我的加密库从mcrypt升级到openssl 问题:是否可以将我的加密库从McRypt升级到OpenSSL?如果是这样,如何?答案:是的,可以将您的Encryption库从McRypt升级到OpenSSL。可以使用openssl。附加说明: [openssl_decrypt()函数要求iv参...
    编程 发布于2025-07-18

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3