[Solved]-Django CMS – check if placeholder is empty

18👍

There is no built-in way to do this at the moment in django-cms, so you have to write a custom template tag. There are some old discussions about this on the django-cms Google Group:

Based on the code in the first discussion, I’ve put together the following Gist:

I use it like so:

{% load extra_cms_tags %}
{% get_placeholder "My Placeholder" as my_placeholder %}

{% if my_placeholder %}
<div>
    {{ my_placeholder }}
</div>
{% endif %}

6👍

If you want additional content to be displayed in case the placeholder is empty, use the or argument and an additional {% endplaceholder %} closing tag. Everything between {% placeholder "..." or %} and {% endplaceholder %} is rendered in the event that the placeholder has no plugins or the plugins do not generate any output.

Example:

{% placeholder "content" or %}

There is no content.

{% endplaceholder %}

5👍

Here’s a very compact solution.

Template filter:

@register.filter('placeholder_is_empty')
def placeholder_is_empty(request, slot):
    page = request.current_page
    placeholder = page.placeholders.get(slot=slot)
    return placeholder.cmsplugin_set.exists()

Usage in template:

{% if request|placeholder_is_empty:'myplaceholder' %}
    <h1>Here comes some content... </h1>
{% endif %}

3👍

Depending on what you are trying to achieve, you can simply use CSS to hide the element if doesn’t have content using the :empty selector. And if you are worried about white spaces you can use Django’s in-build {% spaceless %} template tag to remove them.

So you’d get this template:

{% spaceless %}
<div class="hide_if_empty">
    {% placeholder "my_placeholder" %}
</div>
{% endspaceless %}

And this CSS:

hide_if_empty:empty {
    display: none;
}

Not exactly what was asked for as it doesn’t remove the HTML – but this will solve the most common case where one wants to check if a place holder is empty, and doesn’t require the introduction of a new template tag.

1👍

2023 update

Accepted answer https://stackoverflow.com/a/17148137/5322302 has issues with latest DjangoCMS.

Updated solution (credits for F.B. from DjangoCMS community).

Tested with Django CMS 4.

{% load get_placeholder %}
...
{% get_placeholder "content" as placeholder_content %}
{% if placeholder_content %}
    <div class="my-2">{{ placeholder_content }}</div>
{% endif %}

code of the templatetag .../templatetags/get_placeholder.py

from classytags.arguments import Argument, MultiValueArgument
from classytags.values import StringValue
from django import template
from django.utils.safestring import mark_safe

from cms.models.placeholdermodel import Placeholder as PlaceholderModel
from cms.templatetags.cms_tags import (
    DeclaredPlaceholder,
    Placeholder,
    PlaceholderOptions,
)

register = template.Library()


class RenderGetPlaceholder(Placeholder):
    """
    Render the content of a placeholder to a variable. Can be provided
    with the name of the placholder (i.e. "Header" in the case of a normal
    CMS page) or a template variable containing a placeholder (i.e. myentry.content in the
    case of an external app using a placeholder)

    {% get_placeholder ["string"|placeholder_var] as variable_name %}

    e.g.
    {% load extra_cms_tags %}
    {% get_placeholder "My Placeholder" as my_placeholder %}

    {% if my_placeholder %}
    <div>
        {{ my_placeholder }}
    </div>
    {% endif %}
    """

    name = "get_placeholder"

    options = PlaceholderOptions(
        Argument("name", resolve=True),
        MultiValueArgument("extra_bits", required=False, resolve=False),
        "as",
        Argument("varname", resolve=False, required=True),
        blocks=[
            ("endplaceholder", "nodelist"),
        ],
    )

    def render_tag(self, context, name, extra_bits, varname, nodelist=None):
        if isinstance(name, PlaceholderModel):
            content = name.render(context, None)
        else:
            content = super(RenderGetPlaceholder, self).render_tag(context, name, extra_bits, nodelist)
        context[varname] = mark_safe(content)
        return ""

    def get_declaration(self):
        # Fix some template voodoo causing errors
        slot = self.kwargs["name"].var.var.__str__().strip('"').strip("'")

        return DeclaredPlaceholder(slot=slot, inherit=False)


register.tag(RenderGetPlaceholder)

0👍

Based on the great answer form @Philip Zedler, a solution that works for both placeholder on django-cms pages, but also on placeholders “outside of the cms”.

@register.filter()
def placeholder_empty(page_placeholder, slot=None):
    """
    for page/slot, pass a page object, and a slot name:  
    {% if request.current_page|djangocms_misc_placeholder_empty:"content" %}

    for a outside page placeholder, just the placeholder object:
    {% if object.placeholderfield|djangocms_misc_placeholder_empty %}

    also, with:
    {% with ph_empty=object.placeholderfield|djangocms_misc_placeholder_empty %}
    """
    placeholder = None
    if isinstance(page_placeholder, Placeholder):
        placeholder = page_placeholder
    elif isinstance(page_placeholder, Page):
        page = page_placeholder
        try:
            placeholder = page.placeholders.get(slot=slot)
        except Placeholder.DoesNotExist:
            pass
    if placeholder:
        # // return not placeholder.cmsplugin_set.filter(language=get_language()).exists()
        return not placeholder.cmsplugin_set.exists()
    return False

usage in template

{% if request.current_page|placeholder_empty:'content' %}
    <h1>Fallback!</h1>
{% endif %}

It’s in my djangocms-misc package

0👍

I took the extra compact solution here and created a templatetag that checks if a static placeholder is not empty:

from cms.toolbar.utils import get_toolbar_from_request

@register.filter("static_placeholder_is_not_empty")
def static_placeholder_is_not_empty(request, slot):

    placeholder = StaticPlaceholder.objects.get(code=slot)

    if get_toolbar_from_request(request).edit_mode_active:
        placeholder = placeholder.draft
    else:
        placeholder = placeholder.public

    is_not_empty = len(placeholder.get_plugins(request.LANGUAGE_CODE)) > 0
    return is_not_empty

It’s used like this:

{% load my_new_shiny_templatetag %}

{% if request|static_placeholder_is_not_empty:'my_static_placeholder' %}
  <div class="something">
{% endif %}

{% static_placeholder "my_static_placeholder" %}

{% if request|static_placeholder_is_not_empty:'my_static_placeholder' %}
  </div>
{% endif %}

Leave a comment