SSRによるSROの研究
46073 ワード
週間前にビルを作り始めましたSEO service それは角度のアプリのすべてのSEOのニーズをカバーしています.最後の主題は、Google検索スニペットを生成する構造化データです.
Googleの検索結果を別のスタイルであなたがそれをフィードに応じて結果を表示します.結果をフォーマットするために、GoogleはJSON - LD形式で構造化されたデータを推薦します.
この記事は構造化データの値についてではなく、追加する正しい型でもありません.構造化されたデータをサービス中に整理する方法についてです.
Google Docsでのコード例のテストRich Results Testing ツール-信じないかどうか-警告を生成します.私は前にこれをして、すべての緑のチェックボックスに到達する努力の無駄です.それで、我々はちょうどためします!シンプルに保つ.
メインスクリプトは以下の通りです.
小道具はそれぞれのタイプに固有のものですsearch gallery . また、サブタイプを持つことができます.例えば、
すべてのタイプを1つに置くことができます
他のオプションはindividual item を配列に設定します.
まず、スクリプトを追加する必要があります
少しずつ掘り進むdocs on Google website 次のことを明らかにする. Googleボットは、最初にコンテンツを読み込むためにJavaScriptを実行します. ボットは スパは、それがどのようにスパであろうと、ボット(良いニュース)によって再実行されます ボットはクロール前に最終的なコンテンツを待つ
Duplicate scripts on the same page , 問題ではない これは 負荷に空の配列を追加し、追加して既存の要素を更新する必要はありません. ボットはとにかくページを再読み込みするが、ページのパフォーマンスについては、最初に空にしたいかもしれません. 我々がSSRを実行するならば、再水和の上でスクリプトを複製することは問題でありません、しかし、それは醜いです.それで、我々は1台のプラットホームを目標とするか、既存のスクリプトをチェックします. すべてのことを念頭に置いて、我々は我々のスキーマを追加を開始する準備が整いました.
正しい.一番簡単なロゴから始めましょう.最終的な結果は次のようになります.
ルールは、1つの検索アクションを設定し、1つの文字列をクエリとして受け取ります.たとえば、レストランのアプリケーションでは、この検索URLは動作しません.
URL自体は言語と地域情報を持つことができます.私はこれに反対する何も見つけることができませんでした、しかし、私は言語と地域を無視する例(Adobe)を見ました.それで、私はデフォルト値を使用します.
キーワードで検索する機能を作成します
Googleボットでのスキーマサポートはありません.最も近いものは
これも
The
現在、私は複数のサービスを持っています.
我々
BOTSはそれを理解しているので、サーバープラットフォームは提供するより良い選択です、そして、それはスクリプト内容を得るために再水和を待つ必要はありません.
Googleは新しいタイプのサポートを追加します.対象はタイプdocumented on schema.org . まだサポートされていない型がある場合は、
これをGoogle検索で試してくださいNebula Award for Best Novel 最初の結果はこんな感じです
今すぐページを開き、スニペットを探します.
私はしばらくの間、スニペットを研究して、それの多くの批評を読みました.それに対する大きなポイントは、変化する規則です.今日検証するものは、必ずしも来年を検証しません.それに加えて、あなたの場所にあなたのスニペットを持って誓うことができますが、Googleは期待通りに表示しないように選択します.Googleで何が起こるかについては、Googleにとどまります.ボトムライン?スニペットは大丈夫ですが、あいまいです.シンプルで覚えておきましょう.
Googleはあなたを見つける!
このポストの底に達してくれてありがとう.あなたがバグや蝶を見つけた場合私に知らせてください.
資源 Google snippets Google structured data gallery Walk through All about featured snippets Schema.org types Understanding JavaScript SEO basics Rich Results testing tool StackBlitz
Googleの検索結果を別のスタイルであなたがそれをフィードに応じて結果を表示します.結果をフォーマットするために、GoogleはJSON - LD形式で構造化されたデータを推薦します.
この記事は構造化データの値についてではなく、追加する正しい型でもありません.構造化されたデータをサービス中に整理する方法についてです.
The final result is on StackBlitz
スニペットは難しいです!
Google Docsでのコード例のテストRich Results Testing ツール-信じないかどうか-警告を生成します.私は前にこれをして、すべての緑のチェックボックスに到達する努力の無駄です.それで、我々はちょうどためします!シンプルに保つ.
基礎
メインスクリプトは以下の通りです.
<script type="application/ld+json">
{
"@context": "http://schema.org/",
"@type": "type-from-gallery",
... props
}
</script>
それはどこでも追加することができます、我々は体の端にそれを追加します.小道具はそれぞれのタイプに固有のものですsearch gallery . また、サブタイプを持つことができます.例えば、
Recipe
型にはreview
プロパティです.Review
.すべてのタイプを1つに置くことができます
@graph
他のすべての型を1つのスクリプトに保持するプロパティ.
@graph
is not documented on Google website, I wonder why. It is mentioned on Google Open Source Blog, and testing it on Rich Results Test tool, it works.
他のオプションはindividual item を配列に設定します.
<script type="application/ld+json">
[{
"@context": "http://schema.org/",
"@type": "type-from-gallery",
... props
},
{
"@context": "http://schema.org/",
"@type": "type-from-gallery",
... props
}]
</script>
我々が遵守する必要がある主なガイドラインは、スニペットはユーザーに表示可能なコンテンツの代表である必要があります.まず、スクリプトを追加する必要があります
@graph
配列を返します.コンストラクタで作成されたプライベートメンバーのようです.名前を挙げますsnippet
の代わりにstructured data
誰も見ていないから!export class SeoService {
private _jsonSnippet: HTMLScriptElement;
private createJsonSnippet(): HTMLScriptElement {
const _script = this.doc.createElement('script');
// set attribute to application/ld+json
_script.setAttribute('type', 'application/ld+json');
// append to body and return reference
this.doc.body.appendChild(_script);
return _script;
}
// add script as soon as possible
AddTags() {
// ...
// add json-ld
this._jsonSnippet = this.createJsonSnippet();
}
}
のボットのコンテンツとSSR
少しずつ掘り進むdocs on Google website 次のことを明らかにする.
href
適切なリンクDuplicate scripts on the same page , 問題ではない
ロゴ
正しい.一番簡単なロゴから始めましょう.最終的な結果は次のようになります.
{
"@type": "Organization",
"url": "url associated with organization",
"logo": "logo full url",
"name": "why is google docs ignoring name?"
}
すべてのページに追加する必要はありません/
). スニペットを更新するために、我々は書き換えますtextContent
スクリプトのプロパティ. // SEO Service
setHome() {
// update snippet with logo
const _schema = {
"@type": "Organization",
// url is the most basic in our case, it could be less dynamic
// I am reusing default url, so will refactor this out later
url: toFormat(Config.Seo.baseUrl, Config.Seo.defaultRegion, Config.Seo.defaultLanguage, ''),
// logo must be 112px minimum, svg is acceptable
// add this new key to config.ts
logo: Config.Seo.logoUrl,
// I am including name anyway
"name": RES.SITE_NAME
}
// update script
this.updateJsonSnippet(_schema);
}
private updateJsonSnippet(schema: any) {
// basic, added the schema to an array
const _graph = { '@context': 'https://schema.org', '@graph': [schema] };
// turn into proper JSON
this._jsonSnippet.textContent = JSON.stringify(_graph);
}
// adding defaultUrl and siteUrl and refactoring service
get defaultUrl(): string {
return toFormat(Config.Seo.baseUrl, Config.Seo.defaultRegion, Config.Seo.defaultLanguage, '');
}
get siteUrl(): string {
return toFormat(Config.Seo.baseUrl, Config.Basic.region, Config.Basic.language, '');
}
とHomeComponent
ngOnInit(): void {
this.seoService.setHome();
}
別の基本型に移動するシテリクスサーチボックス
ルールは、1つの検索アクションを設定し、1つの文字列をクエリとして受け取ります.たとえば、レストランのアプリケーションでは、この検索URLは動作しません.
/search?category=chinese&price=low&open=true&nonsmoking=true&query=korma&location=sandiego&page=3
単純なクエリを処理する必要があります./search?query=korma
もちろん、すべてのWebアプリケーションは、独自の目的を持って、あなたのGoogleのリストをユーザーがデフォルトで禁煙を検索できるようにする必要があります、それはあなたのニッチですので.そのような場合、スニペットで指定されたURLはプリセット条件を含んでいるべきです.URL自体は言語と地域情報を持つことができます.私はこれに反対する何も見つけることができませんでした、しかし、私は言語と地域を無視する例(Adobe)を見ました.それで、私はデフォルト値を使用します.
キーワードで検索する機能を作成します
q
), ホームページに次を加えることができます.最終結果は次のようになります {
"@type": "WebSite",
"url": "https://{{default}}.domain.com/{{default}}",
"potentialAction": {
"@type": "SearchAction",
"target": {
"@type": "EntryPoint",
"urlTemplate": "https://{{default}}.domain.com/{{default}}/projects;q={search_term}"
},
"query-input": "required name=search_term"
}
}
Googleは言います:このマークアップをホームページだけに加えてください.Rightteoグーグル我々の中でsetHome
: // ... second schema
const _schema2 = {
'@type': 'Website',
url: this.defaultUrl,
potentialAction: {
'@type': 'SearchAction',
target: {
'@type': 'EntryPoint',
urlTemplate: this.defaultUrl + '?q={serach_term}',
},
'query-input': 'required name=search_term',
},
};
// oh oh! need a way to append
this.updateJsonSnippet(_schema2);
私は、Aに加えるほうを選びます@graph
コレクションは、簡単ですので.書き直しましょうupdate
それを念頭に置いて. // let's keep track of the objects added
private _graphObjects: any[] = [];
private updateJsonSnippet(schema: any) {
// first find the graph objects
const found = this._graphObjects.findIndex(n => n['@type'] === schema['@type']);
// if found replace, else create a new one
if (found > -1) {
this._graphObjects[found] = schema;
} else {
this._graphObjects.push(schema);
}
const _graph = { '@context': 'https://schema.org', '@graph': this._graphObjects };
this._jsonSnippet.textContent = JSON.stringify(_graph);
}
それで、我々は基礎をカバーしました.どのような努力がすべての機能に必要かを見てみましょう.機能のスニペットを設定する
Googleボットでのスキーマサポートはありません.最も近いものは
Article
. 次のような記事の断片を追加しましょう.Psst: Don't lose sleep over this, Google docs change, their recommendations change, and the results are never guaranteed. Stay simple, stay healthy.
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Project title",
"image": "Project image",
"datePublished": "date created",
"author": [{
"@type": "Organization",
"name": "Sekrab Garage",
"url": "https://www.domain.com/en/"
}]
}
だから我々のプロジェクトではsetProject
setProject(project: IProject) {
// ...
this.updateJsonSnippet({
'@type': 'Article',
headline: project.title,
image: project.image,
datePublished: project.dateCreated,
author: [{
'@type': 'Organization',
name: RES.SITE_NAME,
url: this.defaultUrl
}]
});
}
調査する価値があるもう一つの要素は BreadcrumbList
. それはItemList
. 最初の要素はプロジェクトリストへのリンクですcategory
. 第2の要素としてのプロジェクトタイトル.プロジェクトの詳細ページにも表示されます.それで、修正しましょうsetProject
:setProject(project: IProject) {
// ...
this.updateJsonSnippet({
'@type': 'BreadcrumbList',
itemListElement: [{
'@type': 'ListItem',
position: 1,
name: project.category.value,
// the url where users can find the list of projects with matching category
item: this.siteUrl + 'projects?categories=' + project.category.key
}, {
'@type': 'ListItem',
position: 2,
name: project.title
}]
});
}
最後のビットは、検索結果のプロジェクトの一覧ですリストの断片
これも
ItemList
を返します.だから今我々はこのようなタイトルがあるTop 20 Non smoking cafes in Dubai
そして、我々のページは、それらの20のリストを含んでいます、結果として、約束されるように、アイテムの回転木馬でなければなりません.Googleは、すでに独自の機能を提供していない限り.これはほとんどすべての時間です!{
"@type": "ItemList",
"itemListElement": [{
"@type": "ListItem",
// increasing
"position": 1,
// url to result details
"url": "https://domain.com/projects/32342"
}]
}
我々の中でSeoService
// change this to accept projects array
setSearchResults(params: IListParams, projects: IProject[]) {
//...
// for every element, use params to construct url
// region.domain.com/language/projects/id
let i = 1;
// construct the URL
const url =this.siteUrl + 'projects/';
this.updateJsonSnippet({
'@type': 'ItemList',
// I need to pass projects
itemListElement: projects.map(n => {
return {
'@type': 'ListItem',
url: url + n.id,
position: i++
}
}),
});
}
その後、検索List
プロジェクトのコンポーネント、プロジェクトの結果を渡すngOnInit(): void {
// search results component
// ...
// pass projects results
this.seoService.setSearchResults(param, projects);
}
リファクタリングのほとんど
The
SeoService
潜在的に大規模に成長する可能性があります.より大きなプロジェクトでは、機能サービスにスキーマの更新を渡すのはより意味があります.機能のプロパティにアクセスしているので.このアプリでは、私は複数のサービスからの基本を継承にそれを壊すことを選んだSeoService
.現在、私は複数のサービスを持っています.
constructor
は複数回呼び出されます.したがって、コンストラクタのすべては既に何かが起こったかどうかチェックする必要があります.我々
AddTags
関数は、現在のdocument.querySelecor
既にそうする.this.meta.addTags
デザインによって、重複を避ける.それで、我々はセットされます.最後を見るStackBlitz project .SSR
BOTSはそれを理解しているので、サーバープラットフォームは提供するより良い選択です、そして、それはスクリプト内容を得るために再水和を待つ必要はありません.
if (environment.production && this.platform.isBrowser)
// do not add scripts in browser
return;
スクリプトの存在を確認し、再利用することもできます.like we did previously :this._jsonSnippet =
this.doc.querySelector('script[type="application/ld+json"]') ||
this.createJsonSnippet();
SVRが実装されていない場合、ブラウザプラットフォームはHTMLでスクリプトを蓄積し始める.これはクロールに影響しませんが、ページパフォーマンスに影響する可能性があります.追加emptyJsonSnippet
. これはメジャーコンポーネントの前に呼び出されるべきです.// SeoService
protected emptyJsonSnippet() {
// sometimes, in browser platform, we need to empty objects first
this._graphObjects = [];
}
サポートされていない型
Googleは新しいタイプのサポートを追加します.対象はタイプdocumented on schema.org . まだサポートされていない型がある場合は、
schema.org
指示.構造化データを持つGoogleの検索スニペットを超えて他の目的に役立ちます.しかし、ある日、それらのタイプは適切にサポートされます.以下にサポートされていない型の例を示します:// not yet supported by Google
return {
'@type': 'MedicalEntity',
url: url + product.key,
name: product.name,
description: product.description,
image: product.image,
medicineSystem: 'WesternConventional',
relevantSpecialty: product.specialties ? product.specialties.map(n => n.name).join(', ') : null
};
批判
これをGoogle検索で試してくださいNebula Award for Best Novel 最初の結果はこんな感じです
今すぐページを開き、スニペットを探します.
{
"@context": "https:\/\/schema.org",
"@type": "Article",
"name": "Nebula Award for Best Novel",
"url": "https:\/\/en.wikipedia.org\/wiki\/Nebula_Award_for_Best_Novel",
"sameAs": "http:\/\/www.wikidata.org\/entity\/Q266012",
"mainEntity": "http:\/\/www.wikidata.org\/entity\/Q266012",
"author": {
"@type": "Organization",
"name": "Contributors to Wikimedia projects"
},
"publisher": {
"@type": "Organization",
"name": "Wikimedia Foundation, Inc.",
"logo": {
"@type": "ImageObject",
"url": "https:\/\/www.wikimedia.org\/static\/images\/wmf-hor-googpub.png"
}
},
"datePublished": "2004-01-03T16:06:25Z",
"dateModified": "2022-04-04T15:53:53Z",
"image": "https:\/\/upload.wikimedia.org\/wikipedia\/en\/8\/8e\/Nebula_Trophy.jpg",
"headline": "literary award"
}
彼らはマッチしますか.ではなく.私はしばらくの間、スニペットを研究して、それの多くの批評を読みました.それに対する大きなポイントは、変化する規則です.今日検証するものは、必ずしも来年を検証しません.それに加えて、あなたの場所にあなたのスニペットを持って誓うことができますが、Googleは期待通りに表示しないように選択します.Googleで何が起こるかについては、Googleにとどまります.ボトムライン?スニペットは大丈夫ですが、あいまいです.シンプルで覚えておきましょう.
Googleはあなたを見つける!
このポストの底に達してくれてありがとう.あなたがバグや蝶を見つけた場合私に知らせてください.
資源
Reference
この問題について(SSRによるSROの研究), 我々は、より多くの情報をここで見つけました https://dev.to/ayyash/seo-in-angular-with-ssr-part-iii-7efテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol