diff --git a/README.md b/README.md index bb01d71..a45d89d 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,11 @@ Image: https://www.example.com/article-image.jpg Based on [Open Graph protocol](https://ogp.me), the SEO plugin implements required properties and some aditionnals ones: +``` + +``` +`:sitename:`: The `SITENAME` from the Pelican settings. + ``` ``` @@ -293,6 +298,7 @@ og_image: https://www.example.com/og-image.jpg ``` If these metadata are not declared, `:title:`, `:description:`, `:image:` will be filled by the default `Title`, `Description` (Pelican metadata) and `Image` (plugin metadata) if they exist. +If `Description` is not defined, a plain text version of `Summary` will be used instead. ``` diff --git a/pelican/plugins/seo/seo_enhancer/html_enhancer/__init__.py b/pelican/plugins/seo/seo_enhancer/html_enhancer/__init__.py index 6051393..6580aef 100644 --- a/pelican/plugins/seo/seo_enhancer/html_enhancer/__init__.py +++ b/pelican/plugins/seo/seo_enhancer/html_enhancer/__init__.py @@ -1,5 +1,7 @@ """HTML Enhancer : get instances of HTML enhancements.""" +from bs4 import BeautifulSoup + from pelican.contents import Article, Page from .article_schema_creator import ArticleSchemaCreator @@ -9,6 +11,17 @@ from .twitter_cards import TwitterCards +def _get_plain_text_summary(metadata): + """Get content from summary, without HTML tags.""" + + soup = BeautifulSoup( + metadata.get("summary", ""), + "html.parser", + ) + text_summary = soup.get_text().strip() + return text_summary + + class HTMLEnhancer: """HTML Enhancer : get instances of HTML enhancements.""" @@ -63,12 +76,14 @@ def __init__(self, file, output_path, path, open_graph=False, twitter_cards=Fals if open_graph: self.open_graph = OpenGraph( + sitename=_settings.get("SITENAME"), siteurl=_settings.get("SITEURL"), fileurl=_fileurl, file_type=_file_type, title=_metadata.get("og_title") or _title, description=_metadata.get("og_description") - or _metadata.get("description"), + or _metadata.get("description") + or _get_plain_text_summary(_metadata), image=_metadata.get("og_image") or _image, locale=_settings.get("LOCALE"), ) diff --git a/pelican/plugins/seo/seo_enhancer/html_enhancer/open_graph.py b/pelican/plugins/seo/seo_enhancer/html_enhancer/open_graph.py index 58b3ac0..322879b 100644 --- a/pelican/plugins/seo/seo_enhancer/html_enhancer/open_graph.py +++ b/pelican/plugins/seo/seo_enhancer/html_enhancer/open_graph.py @@ -9,8 +9,9 @@ class OpenGraph: """ def __init__( - self, siteurl, fileurl, file_type, title, description, image, locale + self, sitename, siteurl, fileurl, file_type, title, description, image, locale ) -> None: + self.sitename = sitename self.siteurl = siteurl self.fileurl = fileurl self.type = file_type @@ -57,6 +58,9 @@ def create_tags(self) -> dict: """ open_graph_tags = {} + if self.sitename: + open_graph_tags["site_name"] = self.sitename + open_graph_tags["url"] = self._create_absolute_fileurl() open_graph_tags["type"] = self.type diff --git a/pelican/plugins/seo/seo_report/seo_analyzer/__init__.py b/pelican/plugins/seo/seo_report/seo_analyzer/__init__.py index 7156467..bbaa1a2 100644 --- a/pelican/plugins/seo/seo_report/seo_analyzer/__init__.py +++ b/pelican/plugins/seo/seo_report/seo_analyzer/__init__.py @@ -11,7 +11,9 @@ class SEOAnalyzer: def __init__(self, article): self._title = getattr(article, "title", None) - self._description = getattr(article, "description", None) + self._description = getattr(article, "description", None) or getattr( + article, "summary", None + ) self._content = getattr(article, "content", None) self._settings = getattr(article, "settings", None) diff --git a/pelican/plugins/seo/tests/conftest.py b/pelican/plugins/seo/tests/conftest.py index ddae16b..c0aa1aa 100644 --- a/pelican/plugins/seo/tests/conftest.py +++ b/pelican/plugins/seo/tests/conftest.py @@ -75,6 +75,7 @@ def fake_article(): "og_description": "OG Description", "og_image": "https://www.fakesite.com/og-image.jpg", "tw_account": "@TestTWCards", + "summary": "Fake summary", } title = "Fake Title" description = "Fake description" diff --git a/pelican/plugins/seo/tests/test_open_graph.py b/pelican/plugins/seo/tests/test_open_graph.py index 9e8d18a..cefc13c 100644 --- a/pelican/plugins/seo/tests/test_open_graph.py +++ b/pelican/plugins/seo/tests/test_open_graph.py @@ -17,6 +17,7 @@ def test_create_absolute_fileurl(self, fake_article): """ og = OpenGraph( + sitename=None, siteurl=fake_article.settings["SITEURL"], fileurl=fake_article.url, file_type=None, @@ -39,6 +40,7 @@ def test_create_absolute_fileurl_with_site_url_with_path(self, site_url, file_ur slash and a file URL with or without a leading slash properly. """ og = OpenGraph( + sitename=None, siteurl=site_url, fileurl=file_url, file_type=None, @@ -67,6 +69,7 @@ def test_get_locale(self, locale, expected_result): """ og = OpenGraph( + sitename=None, siteurl=None, fileurl=None, file_type=None, @@ -86,6 +89,7 @@ def test_create_tags(self, fake_article): """ og = OpenGraph( + sitename=fake_article.settings["SITENAME"], siteurl=fake_article.settings["SITEURL"], fileurl=fake_article.url, file_type="article", @@ -97,6 +101,7 @@ def test_create_tags(self, fake_article): og_tags = og.create_tags() + assert og_tags["site_name"] == "Fake Site Name" assert og_tags["url"] == "https://www.fakesite.com/fake-title.html" assert og_tags["type"] == "article" assert og_tags["title"] == "OG Title" @@ -111,6 +116,7 @@ def test_create_tags_missing_elements(self, fake_article_missing_elements): """ og = OpenGraph( + sitename=fake_article_missing_elements.settings["SITENAME"], siteurl=fake_article_missing_elements.settings["SITEURL"], fileurl=fake_article_missing_elements.url, file_type="article", @@ -122,6 +128,7 @@ def test_create_tags_missing_elements(self, fake_article_missing_elements): og_tags = og.create_tags() + assert "site_name" not in og_tags assert "title" not in og_tags assert "description" not in og_tags assert "image" not in og_tags diff --git a/pelican/plugins/seo/tests/test_seo_enhancer.py b/pelican/plugins/seo/tests/test_seo_enhancer.py index c05af56..5687eae 100644 --- a/pelican/plugins/seo/tests/test_seo_enhancer.py +++ b/pelican/plugins/seo/tests/test_seo_enhancer.py @@ -233,12 +233,77 @@ def test_add_html_enhancements_to_file_with_open_graph( + + + +

Fake content title

+

Fake content 🙃

+ Fake internal link +

Fake content with inline code

+

Fake content with "Fake inline internal link"

+ + """ + ) + + def test_add_html_enhancements_to_file_with_open_graph_using_summary_for_description( + self, fake_article, fake_seo_enhancer + ): + """ + Test if add_html_to_file with open_graph setting + adds Open Graph tags to HTML files. + """ + + # Remove higher priority values for the og:description tag to force the use of + # the summary from article description. + del fake_article.metadata["og_description"] + del fake_article.description + + path = "fake_output/fake_file.html" + fake_html_enhancements = fake_seo_enhancer.launch_html_enhancer( + file=fake_article, + output_path="fake_output", + path=path, + open_graph=True, + ) + + with patch( + "seo.seo_enhancer.open", mock_open(read_data=fake_article.content) + ) as mocked_open: + mocked_file_handle = mocked_open.return_value + + fake_seo_enhancer.add_html_to_file( + enhancements=fake_html_enhancements, path=path + ) + assert len(mocked_open.call_args_list) == 2 + mocked_file_handle.read.assert_called_once() + mocked_file_handle.write.assert_called_once() + + write_args, _ = mocked_file_handle.write.call_args_list[0] + fake_html_content = write_args[0] + + # The og:description tag should now contain "Fake summary". + assert ( + fake_html_content + == """ + + Fake Title + + + + + + + + + + +

Fake content title

@@ -295,6 +360,7 @@ def test_add_html_enhancements_to_file_with_twitter_cards( +