mirror of https://github.com/halo-dev/halo
refactor: excerpt as the meta description on the page of post and single page (#3745)
#### What type of PR is this? /kind improvement /area core #### What this PR does / why we need it: 将文章摘要作为 meta description 以优化文章页的 SEO how to test it? 查看文章页和自定义页面的 head 中是否具有 `<meta name="description" content="文章摘要"/>` 标签 #### Which issue(s) this PR fixes: Fixes #2682 #### Does this PR introduce a user-facing change? ```release-note 将文章摘要作为 meta description 以优化文章页的 SEO ```pull/3714/head^2
parent
e4338c111e
commit
d7bfbef149
|
@ -1,5 +1,10 @@
|
|||
package run.halo.app.theme.dialect;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
@ -37,10 +42,20 @@ public class ContentTemplateHeadProcessor implements TemplateHeadProcessor {
|
|||
Mono<List<Map<String, String>>> htmlMetasMono = Mono.empty();
|
||||
if (isPostTemplate(context)) {
|
||||
htmlMetasMono = nameMono.flatMap(postFinder::getByName)
|
||||
.map(post -> post.getSpec().getHtmlMetas());
|
||||
.map(post -> {
|
||||
List<Map<String, String>> htmlMetas = post.getSpec().getHtmlMetas();
|
||||
String excerpt =
|
||||
post.getStatus() == null ? null : post.getStatus().getExcerpt();
|
||||
return excerptToMetaDescriptionIfAbsent(htmlMetas, excerpt);
|
||||
});
|
||||
} else if (isPageTemplate(context)) {
|
||||
htmlMetasMono = nameMono.flatMap(singlePageFinder::getByName)
|
||||
.map(page -> page.getSpec().getHtmlMetas());
|
||||
.map(page -> {
|
||||
List<Map<String, String>> htmlMetas = page.getSpec().getHtmlMetas();
|
||||
String excerpt =
|
||||
page.getStatus() == null ? null : page.getStatus().getExcerpt();
|
||||
return excerptToMetaDescriptionIfAbsent(htmlMetas, excerpt);
|
||||
});
|
||||
}
|
||||
|
||||
return htmlMetasMono
|
||||
|
@ -52,6 +67,32 @@ public class ContentTemplateHeadProcessor implements TemplateHeadProcessor {
|
|||
.then();
|
||||
}
|
||||
|
||||
static List<Map<String, String>> excerptToMetaDescriptionIfAbsent(
|
||||
List<Map<String, String>> htmlMetas,
|
||||
String excerpt) {
|
||||
final String excerptNullSafe = StringUtils.defaultString(excerpt);
|
||||
List<Map<String, String>> metas = new ArrayList<>(defaultIfNull(htmlMetas, List.of()));
|
||||
metas.stream()
|
||||
.filter(map -> Meta.DESCRIPTION.equals(map.get(Meta.NAME)))
|
||||
.distinct()
|
||||
.findFirst()
|
||||
.ifPresentOrElse(map ->
|
||||
map.put(Meta.CONTENT, defaultIfBlank(map.get(Meta.CONTENT), excerptNullSafe)),
|
||||
() -> {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put(Meta.NAME, Meta.DESCRIPTION);
|
||||
map.put(Meta.CONTENT, excerptNullSafe);
|
||||
metas.add(map);
|
||||
});
|
||||
return metas;
|
||||
}
|
||||
|
||||
interface Meta {
|
||||
String DESCRIPTION = "description";
|
||||
String NAME = "name";
|
||||
String CONTENT = "content";
|
||||
}
|
||||
|
||||
private String headMetaBuilder(List<Map<String, String>> htmlMetas) {
|
||||
if (htmlMetas == null) {
|
||||
return StringUtils.EMPTY;
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package run.halo.app.theme.dialect;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link ContentTemplateHeadProcessor}.
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.5.0
|
||||
*/
|
||||
class ContentTemplateHeadProcessorTest {
|
||||
|
||||
@Nested
|
||||
class ExcerptToMetaDescriptionTest {
|
||||
@Test
|
||||
void toMetaWhenExcerptIsNull() {
|
||||
List<Map<String, String>> htmlMetas = new ArrayList<>();
|
||||
htmlMetas.add(createMetaMap("keywords", "test"));
|
||||
var result = ContentTemplateHeadProcessor.excerptToMetaDescriptionIfAbsent(htmlMetas,
|
||||
null);
|
||||
assertThat(result).hasSize(2);
|
||||
assertThat(result.get(0)).containsEntry("name", "keywords");
|
||||
assertThat(result.get(1)).containsEntry("name", "description")
|
||||
.containsEntry("content", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toMetaWhenWhenHtmlMetaIsNull() {
|
||||
var result = ContentTemplateHeadProcessor.excerptToMetaDescriptionIfAbsent(null,
|
||||
null);
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0)).containsEntry("name", "description")
|
||||
.containsEntry("content", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toMetaWhenWhenExcerptNotEmpty() {
|
||||
List<Map<String, String>> htmlMetas = new ArrayList<>();
|
||||
htmlMetas.add(createMetaMap("keywords", "test"));
|
||||
var result = ContentTemplateHeadProcessor.excerptToMetaDescriptionIfAbsent(htmlMetas,
|
||||
"test excerpt");
|
||||
assertThat(result).hasSize(2);
|
||||
assertThat(result.get(0)).containsEntry("name", "keywords");
|
||||
assertThat(result.get(1)).containsEntry("name", "description")
|
||||
.containsEntry("content", "test excerpt");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toMetaWhenWhenDescriptionExistsAndEmpty() {
|
||||
List<Map<String, String>> htmlMetas = new ArrayList<>();
|
||||
htmlMetas.add(createMetaMap("keywords", "test"));
|
||||
htmlMetas.add(createMetaMap("description", ""));
|
||||
var result = ContentTemplateHeadProcessor.excerptToMetaDescriptionIfAbsent(htmlMetas,
|
||||
"test excerpt");
|
||||
assertThat(result).hasSize(2);
|
||||
assertThat(result.get(0)).containsEntry("name", "keywords");
|
||||
assertThat(result.get(1)).containsEntry("name", "description")
|
||||
.containsEntry("content", "test excerpt");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toMetaWhenWhenDescriptionExistsAndNotEmpty() {
|
||||
List<Map<String, String>> htmlMetas = new ArrayList<>();
|
||||
htmlMetas.add(createMetaMap("keywords", "test"));
|
||||
htmlMetas.add(createMetaMap("description", "test description"));
|
||||
var result = ContentTemplateHeadProcessor.excerptToMetaDescriptionIfAbsent(htmlMetas,
|
||||
"test excerpt");
|
||||
assertThat(result).hasSize(2);
|
||||
assertThat(result.get(0)).containsEntry("name", "keywords");
|
||||
assertThat(result.get(1)).containsEntry("name", "description")
|
||||
.containsEntry("content", "test description");
|
||||
}
|
||||
|
||||
Map<String, String> createMetaMap(String nameValue, String contentValue) {
|
||||
Map<String, String> metaMap = new HashMap<>();
|
||||
metaMap.put("name", nameValue);
|
||||
metaMap.put("content", contentValue);
|
||||
return metaMap;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -169,6 +169,7 @@ class HaloProcessorDialectTest {
|
|||
<title>Post</title>
|
||||
<meta content="post-meta-V1" name="post-meta-V1" />
|
||||
<meta content="post-meta-V2" name="post-meta-V2" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="global-head-test" content="test" />
|
||||
<meta name="content-head-test" content="test" />
|
||||
</head>
|
||||
|
|
Loading…
Reference in New Issue