Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: content page meta tags now override global injected (#4069)
#### What type of PR is this? /kind improvement /area core /milestone 2.7.x #### What this PR does / why we need it: 修复文章页 HTML Meta 标签重复问题 see #4049 for more details. #### Which issue(s) this PR fixes: Fixes #4049 #### Does this PR introduce a user-facing change? ```release-note 修复文章页 Meta Description 标签重复问题 ```
- Loading branch information
Showing
9 changed files
with
321 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
application/src/main/java/run/halo/app/theme/dialect/DuplicateMetaTagProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package run.halo.app.theme.dialect; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Comparator; | ||
import java.util.LinkedHashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import lombok.AllArgsConstructor; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.springframework.core.annotation.Order; | ||
import org.springframework.stereotype.Component; | ||
import org.thymeleaf.context.ITemplateContext; | ||
import org.thymeleaf.model.IModel; | ||
import org.thymeleaf.model.ITemplateEvent; | ||
import org.thymeleaf.model.IText; | ||
import org.thymeleaf.processor.element.IElementModelStructureHandler; | ||
import reactor.core.publisher.Mono; | ||
|
||
/** | ||
* <p>This processor will remove the duplicate meta tag with the same name in head tag and only | ||
* keep the last one.</p> | ||
* <p>This processor will be executed last.</p> | ||
* | ||
* @author guqing | ||
* @since 2.0.0 | ||
*/ | ||
@Order | ||
@Component | ||
@AllArgsConstructor | ||
public class DuplicateMetaTagProcessor implements TemplateHeadProcessor { | ||
static final Pattern META_PATTERN = Pattern.compile("<meta\\s+name=\"(\\w+)\"(.*?)>"); | ||
|
||
@Override | ||
public Mono<Void> process(ITemplateContext context, IModel model, | ||
IElementModelStructureHandler structureHandler) { | ||
IModel newModel = context.getModelFactory().createModel(); | ||
|
||
Map<String, IndexedModel> uniqueMetaTags = new LinkedHashMap<>(); | ||
List<IndexedModel> otherModel = new ArrayList<>(); | ||
for (int i = 0; i < model.size(); i++) { | ||
ITemplateEvent templateEvent = model.get(i); | ||
// If the current node is a text node, it is processed separately. | ||
// Because the text node may contain multiple meta tags. | ||
if (templateEvent instanceof IText textNode) { | ||
String text = textNode.getText(); | ||
Matcher matcher = META_PATTERN.matcher(text); | ||
while (matcher.find()) { | ||
String tagLine = matcher.group(0); | ||
String nameAttribute = matcher.group(1); | ||
IText metaTagNode = context.getModelFactory().createText(tagLine); | ||
uniqueMetaTags.put(nameAttribute, new IndexedModel(i, metaTagNode)); | ||
text = text.replace(tagLine, ""); | ||
} | ||
if (StringUtils.isNotBlank(text)) { | ||
IText otherText = context.getModelFactory() | ||
.createText(text); | ||
otherModel.add(new IndexedModel(i, otherText)); | ||
} | ||
} else { | ||
otherModel.add(new IndexedModel(i, templateEvent)); | ||
} | ||
} | ||
|
||
otherModel.addAll(uniqueMetaTags.values()); | ||
otherModel.stream().sorted(Comparator.comparing(IndexedModel::index)) | ||
.map(IndexedModel::templateEvent) | ||
.forEach(newModel::add); | ||
|
||
model.reset(); | ||
model.addModel(newModel); | ||
return Mono.empty(); | ||
} | ||
|
||
record IndexedModel(int index, ITemplateEvent templateEvent) { | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.