geosolutions-it/geonode-subsites

Implement templates per subiste

Closed this issue · 5 comments

We want to be able to customize templates per subsite (geonode_config, home, snippets, etc.).
Since subsites are data models, we don't have a real folder per subsite. My proposal is to make the module look for a folder named subsite.slug under the subsites/templates/ folder and use it as the root of the subsite's templates.

For example for website "site_1" its home template will be picked from subsites/templates/site_1/home.html if it exists. Otherwise the normal template lookup will be used.

Hi @giohappy
I tried locally to find an approach for this, and I have come out so far.

NOTE: I started only with _geonode_config.html

The file will be updated as follows:

{% extends 'geonode-mapstore-client/_geonode_config.html' %}
{% load i18n %}
{% load static %}
{% load custom_tags %}

{% block override_local_config %}
{% load_subsite_info request as subsite_slug%}

{% custom_file_exists subsite_slug 'geonode_config' as CUSTOM_TEMPLATE_EXISTS %}

{{CUSTOM_TEMPLATE_EXISTS}}

{% if CUSTOM_TEMPLATE_EXISTS %}
    {% include CUSTOM_TEMPLATE_EXISTS with menu_item=menu_item %}
{% else %}
<script>
    window.__GEONODE_CONFIG__.overrideLocalConfig = function(localConfig, _) {
        // Here the localConfig can be overridden and/or extended
        localConfig.geoNodeApi.endpointV1 = "/{{custom_theme.slug}}/api/"
        localConfig.geoNodeApi.endpointV2 = "/{{custom_theme.slug}}/api/v2"
        return localConfig;
    };
</script>
{% endif %}

{% endblock %}

The subsite templates structure will be like the following:

➜  templates git:(ISSUE_2) ✗ tree ../templates 
../templates
├── geonode-mapstore-client
│   ├── _geonode_config.html
│   └── snippets
│       ├── brand_navbar.html
│       ├── search_bar.html
│       └── topbar.html
└── subsite_1
    └── _geonode_config.html

In a few words, when the template is called, the CUSTOM_TEMPLATE_EXISTS checks if an overriding file exists for the specific subsite. If not the default local_config for the subsite is called. Otherwise, the if exists, the CUSTOM_TEMPLATE_EXISTS will store the path of the file to be included by the django {% include %} template tag

FYI:

  • load_subsite_info: is a custom tag that retrieves the slug of the subsite that is called
  • CUSTOM_TEMPLATE_EXISTS: is a custom tag that checks if for the given subsite a template exists

In the end the HTML code needed to make this happen is the following:

{% extends 'original/geonode/path/to/the/html' %}
{% load custom_tags %} <!-- needed to load the subsite tags -->

{% block blockname_we_want_to_override %}
{% load_subsite_info request as subsite_slug%} <!-- needed get the subsite_slug -->

{% custom_file_exists subsite_slug 'geonode_config' as CUSTOM_TEMPLATE_EXISTS %} <!-- needed get override file -->

{% if CUSTOM_TEMPLATE_EXISTS %}
    {% include CUSTOM_TEMPLATE_EXISTS %}
{% else %}
<!-- original behavior we want to maintain -->
{% endif %}

{% endblock %}

This is a possible approach, I'll try to find something else too

@mattiagiupponi if I understand it correctly the following subtree will be under the subsites module:

➜  templates git:(ISSUE_2) ✗ tree ../templates 
../templates
├── geonode-mapstore-client
│   ├── _geonode_config.html
│   └── snippets
│       ├── brand_navbar.html
│       ├── search_bar.html
│       └── topbar.html
└── subsite_1
    └── _geonode_config.html

and we must implement a template file under subsites/templates/ for every template we want to be able to override per subsit e, correct?

Well, it's not that great from the developer's point of view, since if I want to override a snippet not included in the geonode-subsites module I cannot do it unless I extend geonode-subsites.

Isn't there a way to hijack the template rendering inside the views, rather than using template conditionals?

I was trying to avoid the override of too many URLs, but yes this could be another option.
I'll try to make a test on my local env to test it out

@giohappy follows a second idea about how to handle the subsite template.
In few words a new TemplateEngine and a CustomLoader is available in the subsite app.
This still needs some work but should give you an overall idea.

In this way the bakcend will dynamically load the template (if exists) based on the subapp that is called.

The PR in draft is here: #3

Hi @giohappy
I just update the proposal about this issue.
In the end we debug together the issue, but better to give a quick sum-up.

The approach we decided is the following as first implementation:

  • create a new render function that is going to be used for the subsite only
  • the render function will intiiate from scratch a new instance of the DjangoTemplates engine with its parameter
  • We inject dinamically (based on the subsite) the path that contains the template for the specific subsite that the user is asking for
  • The default DjangoTemplate engine will take care of thre rendering

I also update the README and created a specific one for the templates

The PR is ready for a review #4