Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let user provide default values of html metatags #6089

Open
TormodLandet opened this issue Feb 19, 2019 · 3 comments
Open

Let user provide default values of html metatags #6089

TormodLandet opened this issue Feb 19, 2019 · 3 comments
Labels
builder:html type:enhancement enhance or introduce a new feature

Comments

@TormodLandet
Copy link
Contributor

Sphinx and docutils provide the meta directive where arbitrary HMTL metadata can be set, such as description, og:image, og:title etc. This can be used to set per-document metadata, but there is no facility (that I have been able to find) to provide default values for these fields.

Best solution: Provide a dictionary in the conf file that gives default values for the html meta data that can be overridden by the meta directive for specific documents

Alternative solution: make the metatags template variable available as a dictionary, it is a pre-rendered string. Right now I parse this string to figure out if there have been any meta overrides defined in the local document. This is of course an ugly hack. The best would be to provide this only as a dictionary, but that is probably not very backwards compatible with any existing theme ... It could be that making metatags a special dict that implements __str__ could maybe work? Anyway, providing overridable default values would be preferable.

For context: Providing proper html metadata is good for search engines, and providing OpenGraph og:* metadata lets web pages make links to the documentation that looks nice and attractive for sharing on Twitter, Facebook, LinkedIn and other pages that provide OpenGraph support.

@TormodLandet TormodLandet added the type:enhancement enhance or introduce a new feature label Feb 19, 2019
@tk0miya
Copy link
Member

tk0miya commented Feb 22, 2019

About OGP, we are waiting for the next release of docutils (see #2645).

Note: As a workaround, you can add meta tags as you like with custom template.

# in _template/layout.html
{% extends "alabaster/layout.html" %}
{% block extrahead %}
    <meta property="og:title" content="ogp title">
{% endblock %}

@TormodLandet
Copy link
Contributor Author

Yeah, I use meta tags directly in the template, but it is rather ugly to be able to override this from the meta directive.

First I need to provide a function in conf.pyto check if the rst file overrides the description using a meta directive:

def get_meta_tag_content(name, html_string):
    """
    Parse pre-rendered meta tags to find name->content mappings

    Given input arguments
        name='myname',
        html_string='<... name="myname" ... content="a" ...>',
    Return the string 'a'.
    If the requested name is not found, return the empty string
    """
    if not html_string or '<' not in html_string:
        return ''
    for tag in html_string.split('<')[1:]:
        # Check that we can expect to be able to parse this tag
        if 'name="' not in tag:
            print('ERROR: metatag without name found: %r' % tag)
            print('ERROR: html_string=%r' % html_string)
            continue
        if 'content="' not in tag:
            print('ERROR: metatag without content found: %r' % tag)
            print('ERROR: html_string=%r' % html_string)
            continue

        # Parse the generated HTML and check for the correct tag name
        tag_name = tag.split('name="')[1].split('"')[0]
        tag_content = tag.split('content="')[1].split('"')[0]
        if tag_name == name:
            return tag_content
    return ''


html_context = {
    'default_description': 'This is the default description',
    'get_meta_tag_content': get_meta_tag_content,
}

And then the template uses this to either show the default description, or the meta directive description:

{# Make sure the metatags variable is present, also if the meta directive has not been used #}
{% if metatags is not defined %}
{% set metatags = '' %}
{% endif %}

{# Use the meta RST directive description if defined, otherwise use the default description #}
{% set page_description = get_meta_tag_content('description', metatags) %}
{% if not page_description %}
{% set page_description = default_description %}
{% set metatags = metatags + '<meta name="description" content="%s">' % page_description %}
{% endif %}

...

<meta property="og:title" content="{{ title|striptags|e }}">
<meta property="og:description" content="{{ page_description }}">

This would be much easier if the meta directive could be configured with default values.

PS: The whole thing can be seen in context here https://bitbucket.org/ocellarisproject/ocellaris/src/master/documentation/_templates/layout.html which is rendered here: https://www.ocellaris.org/

@tk0miya
Copy link
Member

tk0miya commented Mar 23, 2019

As a workaround, you can use following extension. It adds og_title and og_description config variables. And they can be overridden via bibliographic fields (refs)

import html


def on_html_page_context(app, pagename, templatename, ctx, doctree):
    if doctree:
        metadata = app.env.metadata.get(pagename, {})

        title = metadata.get('og:title', app.config.og_title)
        if not title:
            title = ctx['title']

        if title:
            ctx['metatags'] += ('\n    <meta property="og:title" content="%s">' % html.escape(title))

        description = metadata.get('og:description', app.config.og_description)
        if description:
            ctx['metatags'] += ('\n    <meta property="og:description" content="%s">' % html.escape(description))


def setup(app):
    app.add_config_value('og_title', None, 'html')
    app.add_config_value('og_description', None, 'html')
    app.connect('html-page-context', on_html_page_context)

This is a scribbling code. So I can't promise you that this will be merged into Sphinx core in future. (At least, I know this will conflicts with meta directive.) But this will help you at this moment.

Thanks,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
builder:html type:enhancement enhance or introduce a new feature
Projects
None yet
Development

No branches or pull requests

2 participants