Exemple #1
0
def get_placeholder_content(context, request, current_page, name, inherit, default):
    edit_mode = getattr(request, 'toolbar', None) and getattr(request.toolbar, 'edit_mode')
    pages = [current_page]
    # don't display inherited plugins in edit mode, so that the user doesn't
    # mistakenly edit/delete them. This is a fix for issue #1303. See the discussion
    # there for possible enhancements
    if inherit and not edit_mode:
        pages = chain([current_page], list(reversed(current_page.get_cached_ancestors())))
    for page in pages:
        placeholder = _get_placeholder(current_page, page, context, name)
        if placeholder is None:
            continue
        if not edit_mode and get_cms_setting('PLACEHOLDER_CACHE'):
            if hasattr(placeholder, 'content_cache'):
                return mark_safe(placeholder.content_cache)
            if not hasattr(placeholder, 'cache_checked'):
                cached_value = get_placeholder_cache(placeholder, get_language())
                if cached_value is not None:
                    restore_sekizai_context(context, cached_value['sekizai'])
                    return mark_safe(cached_value['content'])
        if not get_plugins(request, placeholder, page.get_template()):
            continue
        content = render_placeholder(placeholder, context, name)
        if content:
            return content
            # if we reach this point, we have an empty or non-existant placeholder
            # call _get_placeholder again to get the placeholder properly rendered
            # in frontend editing
    placeholder = _get_placeholder(current_page, current_page, context, name)
    return render_placeholder(placeholder, context, name, default=default)
Exemple #2
0
def get_placeholder_content(context, request, current_page, name, inherit,
                            default):
    from django.core.cache import cache
    edit_mode = getattr(request, 'toolbar', None) and getattr(
        request.toolbar, 'edit_mode')
    pages = [current_page]
    # don't display inherited plugins in edit mode, so that the user doesn't
    # mistakenly edit/delete them. This is a fix for issue #1303. See the discussion
    # there for possible enhancements
    if inherit and not edit_mode:
        pages = chain([current_page],
                      current_page.get_cached_ancestors(ascending=True))
    for page in pages:
        placeholder = _get_placeholder(current_page, page, context, name)
        if placeholder is None:
            continue
        if not edit_mode and get_cms_setting('PLACEHOLDER_CACHE'):
            if hasattr(placeholder, 'content_cache'):
                return mark_safe(placeholder.content_cache)
            if not hasattr(placeholder, 'cache_checked'):
                cache_key = placeholder.get_cache_key(get_language())
                cached_value = cache.get(cache_key)
                if not cached_value is None:
                    restore_sekizai_context(context, cached_value['sekizai'])
                    return mark_safe(cached_value['content'])
        if not get_plugins(request, placeholder, page.get_template()):
            continue
        content = render_placeholder(placeholder, context, name)
        if content:
            return content
            # if we reach this point, we have an empty or non-existant placeholder
            # call _get_placeholder again to get the placeholder properly rendered
            # in frontend editing
    placeholder = _get_placeholder(current_page, current_page, context, name)
    return render_placeholder(placeholder, context, name, default=default)
    def get_plugins_to_render(self, placeholder, language, template):
        from cms.utils.plugins import get_plugins

        plugins = get_plugins(
            request=self.request,
            placeholder=placeholder,
            template=template,
            lang=language,
        )
        return plugins
Exemple #4
0
    def render_tag(self,
                   context,
                   name,
                   page_lookup,
                   varname,
                   extra_bits,
                   nodelist=None):
        """
        Retrieves the placeholder's plugins and set them as a variable in the template context.
        If the placeholder is empty, render the block as fallback content and return the
        resulting HTML.
        If the placholder is editable, the edit script and markup are added to the HTML content.
        """
        content = ""
        request = context.get("request")

        if request:

            page = _get_page_by_untyped_arg(page_lookup, request,
                                            get_site_id(None))

            try:
                placeholder = page.placeholders.get(slot=name)
            except ObjectDoesNotExist:
                context[varname] = []
                return ""
            else:
                context[varname] = [
                    cms_plugin.get_plugin_instance()[0]
                    for cms_plugin in get_plugins(
                        request, placeholder, template=page.get_template())
                ]

            # Default content if there is no plugins in the placeholder
            if not context[varname] and nodelist:
                content = nodelist.render(context)

            # Add the edit script and markup to the content, only if the placeholder is editable
            # and the visited page is the one on which the placeholder is declared.
            toolbar = get_toolbar_from_request(request)
            if placeholder.page == request.current_page and toolbar.edit_mode_active:
                renderer = toolbar.get_content_renderer()
                data = renderer.get_editable_placeholder_context(placeholder,
                                                                 page=page)
                data["content"] = content
                content = renderer.placeholder_edit_template.format(**data)

        return content
Exemple #5
0
 def get_nodes(self, request):
     nodes = []
     glasfaser_cms = 'ungleich_page/glasfaser_cms_page.html'
     if (request and request.current_page
             and request.current_page.get_template() == glasfaser_cms):
         template_context = {
             "request": request,
         }
         placeholder_name_list = [
             'Top Section', 'Middle Section', 'Glasfaser Services',
             'Glasfaser About', 'Contact Section'
         ]
         plugins_list = [
             'SectionWithImage', 'UngelichContactUsSection',
             'UngelichTextSection', 'Service', 'About'
         ]
         for placeholder_name in placeholder_name_list:
             placeholder = _get_placeholder(request.current_page,
                                            request.current_page,
                                            template_context,
                                            placeholder_name)
             plugins = get_plugins(request, placeholder,
                                   request.current_page.get_template())
             for plugin in plugins:
                 if type(plugin).__name__ in plugins_list:
                     section_hash = request.build_absolute_uri()
                     if hasattr(plugin, 'menu_text'):
                         menu_text = plugin.menu_text
                         if menu_text.strip() == '':
                             continue
                         menu_words = menu_text.split()
                         if len(menu_words) > 0:
                             section_hash = '{}#{}'.format(
                                 section_hash, menu_words[0])
                     else:
                         continue
                     newnode = NavigationNode(menu_text,
                                              url=section_hash,
                                              id="{}-{}".format(
                                                  request.current_page.id,
                                                  plugin.id))
                     nodes.append(newnode)
     return nodes
Exemple #6
0
def media_plugins(context, post):
    """
    Extract :py:class:`djangocms_blog.media.base.MediaAttachmentPluginMixin`
    plugins from the ``media`` placeholder of the provided post.

    They can be rendered with ``render_plugin`` templatetag:

    .. code-block: python

        {% media_plugins post as media_plugins %}
        {% for plugin in media_plugins %}{% render_plugin plugin %}{% endfor %}

    :param context: template context
    :type context: dict
    :param post: post instance
    :type post: :py:class:`djangocms_blog.models.Post`
    :return: list of :py:class:`djangocms_blog.media.base.MediaAttachmentPluginMixin` plugins
    :rtype: List[djangocms_blog.media.base.MediaAttachmentPluginMixin]
    """
    request = context["request"]
    if post.media.get_plugins().exists():
        return get_plugins(request, post.media, None)
    return []
Exemple #7
0
def render_placeholder(placeholder,
                       context_to_copy,
                       name_fallback="Placeholder",
                       lang=None,
                       default=None):
    """
    Renders plugins for a placeholder on the given page using shallow copies of the
    given context, and returns a string containing the rendered output.
    """
    if not placeholder:
        return
    from cms.utils.plugins import get_plugins
    context = context_to_copy
    context.push()
    request = context['request']
    if not hasattr(request, 'placeholder'):
        request.placeholders = []
    request.placeholders.append(placeholder)
    if hasattr(placeholder, 'content_cache'):
        return mark_safe(placeholder.content_cache)
    page = placeholder.page if placeholder else None
    # It's kind of duplicate of the similar call in `get_plugins`, but it's required
    # to have a valid language in this function for `get_fallback_languages` to work
    if lang:
        save_language = lang
    else:
        lang = get_language_from_request(request)
        save_language = lang

    # Prepend frontedit toolbar output if applicable
    edit = False
    toolbar = getattr(request, 'toolbar', None)

    if getattr(toolbar, 'edit_mode', False):
        edit = True
    if edit:
        from cms.middleware.toolbar import toolbar_plugin_processor

        processors = (toolbar_plugin_processor, )
    else:
        processors = None
    from django.core.cache import cache
    if get_cms_setting('PLACEHOLDER_CACHE'):
        cache_key = placeholder.get_cache_key(lang)
        if not edit and placeholder and not hasattr(placeholder,
                                                    'cache_checked'):
            cached_value = cache.get(cache_key)
            if not cached_value is None:
                restore_sekizai_context(context, cached_value['sekizai'])
                return mark_safe(cached_value['content'])
    if page:
        template = page.template
    else:
        template = None

    plugins = [
        plugin
        for plugin in get_plugins(request, placeholder, template, lang=lang)
    ]

    # Add extra context as defined in settings, but do not overwrite existing context variables,
    # since settings are general and database/template are specific
    # TODO this should actually happen as a plugin context processor, but these currently overwrite
    # existing context -- maybe change this order?
    slot = getattr(placeholder, 'slot', None)
    extra_context = {}
    if slot:
        extra_context = get_placeholder_conf("extra_context", slot, template,
                                             {})
    for key, value in extra_context.items():
        if key not in context:
            context[key] = value

    content = []
    watcher = Watcher(context)
    content.extend(render_plugins(plugins, context, placeholder, processors))
    toolbar_content = ''

    if edit:
        if not hasattr(request.toolbar, 'placeholders'):
            request.toolbar.placeholders = {}
        if placeholder.pk not in request.toolbar.placeholders:
            request.toolbar.placeholders[placeholder.pk] = placeholder
    if edit:
        toolbar_content = mark_safe(
            render_placeholder_toolbar(placeholder, context, name_fallback,
                                       save_language))
    if content:
        content = mark_safe("".join(content))
    elif default:
        #should be nodelist from a template
        content = mark_safe(default.render(context_to_copy))
    else:
        content = ''
    context['content'] = content
    context['placeholder'] = toolbar_content
    context['edit'] = edit
    result = render_to_string("cms/toolbar/content.html", context)
    changes = watcher.get_changes()
    if placeholder and not edit and placeholder.cache_placeholder and get_cms_setting(
            'PLACEHOLDER_CACHE'):
        cache.set(cache_key, {
            'content': result,
            'sekizai': changes
        },
                  get_cms_setting('CACHE_DURATIONS')['content'])
    context.pop()
    return result
def render_placeholder(placeholder, context_to_copy,
        name_fallback="Placeholder", lang=None, default=None, editable=True,
        use_cache=True):
    """
    Renders plugins for a placeholder on the given page using shallow copies of the
    given context, and returns a string containing the rendered output.

    Set editable = False to disable front-end editing for this placeholder
    during rendering. This is primarily used for the "as" variant of the
    render_placeholder tag.
    """
    if not placeholder:
        return
    from cms.utils.plugins import get_plugins
    context = context_to_copy
    context.push()
    request = context['request']
    if not hasattr(request, 'placeholders'):
        request.placeholders = []
    if placeholder.has_change_permission(request):
        request.placeholders.append(placeholder)
    if hasattr(placeholder, 'content_cache'):
        return mark_safe(placeholder.content_cache)
    page = placeholder.page if placeholder else None
    # It's kind of duplicate of the similar call in `get_plugins`, but it's required
    # to have a valid language in this function for `get_fallback_languages` to work
    if lang:
        save_language = lang
    else:
        lang = get_language_from_request(request)
        save_language = lang

    # Prepend frontedit toolbar output if applicable
    toolbar = getattr(request, 'toolbar', None)
    if getattr(toolbar, 'edit_mode', False) and getattr(placeholder, 'is_editable', True) and editable:
        from cms.middleware.toolbar import toolbar_plugin_processor
        processors = (toolbar_plugin_processor,)
        edit = True
    else:
        processors = None
        edit = False
    from django.core.cache import cache
    if get_cms_setting('PLACEHOLDER_CACHE') and use_cache:
        cache_key = placeholder.get_cache_key(lang)
        if not edit and placeholder and not hasattr(placeholder, 'cache_checked'):
            cached_value = cache.get(cache_key)
            if not cached_value is None:
                restore_sekizai_context(context, cached_value['sekizai'])
                return mark_safe(cached_value['content'])
    if page:
        template = page.template
    else:
        template = None

    plugins = [plugin for plugin in get_plugins(request, placeholder, template, lang=lang)]

    # Add extra context as defined in settings, but do not overwrite existing context variables,
    # since settings are general and database/template are specific
    # TODO this should actually happen as a plugin context processor, but these currently overwrite
    # existing context -- maybe change this order?
    slot = getattr(placeholder, 'slot', None)
    extra_context = {}
    if slot:
        extra_context = get_placeholder_conf("extra_context", slot, template, {})
    for key, value in extra_context.items():
        if key not in context:
            context[key] = value

    content = []
    watcher = Watcher(context)
    content.extend(render_plugins(plugins, context, placeholder, processors))
    toolbar_content = ''

    if edit and editable:
        if not hasattr(request.toolbar, 'placeholders'):
            request.toolbar.placeholders = {}
        if placeholder.pk not in request.toolbar.placeholders:
            request.toolbar.placeholders[placeholder.pk] = placeholder
        toolbar_content = mark_safe(render_placeholder_toolbar(placeholder, context, name_fallback, save_language))
    if content:
        content = mark_safe("".join(content))
    elif default:
        #should be nodelist from a template
        content = mark_safe(default.render(context_to_copy))
    else:
        content = ''
    context['content'] = content
    context['placeholder'] = toolbar_content
    context['edit'] = edit
    result = render_to_string("cms/toolbar/content.html", context)
    changes = watcher.get_changes()
    if placeholder and not edit and placeholder.cache_placeholder and get_cms_setting('PLACEHOLDER_CACHE') and use_cache:
        cache.set(cache_key, {'content': result, 'sekizai': changes}, get_cms_setting('CACHE_DURATIONS')['content'])
    context.pop()
    return result
    def render_placeholder(self, placeholder, context, language=None, page=None,
                           editable=False, use_cache=False, nodelist=None, width=None):
        from sekizai.helpers import Watcher
        from cms.utils.plugins import get_plugins

        language = language or self.request_language
        editable = editable and self._placeholders_are_editable

        if use_cache and not editable and placeholder.cache_placeholder:
            use_cache = self.placeholder_cache_is_enabled()
        else:
            use_cache = False

        if page:
            site_id = page.site_id
            template = page.get_template()
        else:
            site_id = get_site_id(None)
            template = None

        if use_cache:
            cached_value = self._get_cached_placeholder_content(
                placeholder=placeholder,
                site_id=site_id,
                language=language,
            )
        else:
            cached_value = None

        if cached_value is not None:
            # User has opted to use the cache
            # and there is something in the cache
            restore_sekizai_context(context, cached_value['sekizai'])
            return mark_safe(cached_value['content'])

        context.push()

        width = width or placeholder.default_width

        if width:
            context['width'] = width

        # Add extra context as defined in settings, but do not overwrite existing context variables,
        # since settings are general and database/template are specific
        # TODO this should actually happen as a plugin context processor, but these currently overwrite
        # existing context -- maybe change this order?
        for key, value in placeholder.get_extra_context(template).items():
            if key not in context:
                context[key] = value

        if use_cache:
            watcher = Watcher(context)

        plugins = get_plugins(
            request=self.request,
            placeholder=placeholder,
            template=template,
            lang=language,
        )

        if plugins:
            plugin_content = self.render_plugins(
                plugins=plugins,
                context=context,
                placeholder=placeholder,
                editable=editable,
            )
            placeholder_content = ''.join(plugin_content)
        elif nodelist:
            # should be nodelist from a template
            placeholder_content = nodelist.render(context)
        else:
            placeholder_content = ''

        if use_cache:
            content = {
                'content': placeholder_content,
                'sekizai': watcher.get_changes(),
            }
            set_placeholder_cache(
                placeholder,
                lang=language,
                site_id=site_id,
                content=content,
                request=self.request,
            )

        if editable:
            toolbar_content = self.render_editable_placeholder(
                placeholder=placeholder,
                context=context,
                language=language,
            )
        else:
            toolbar_content = ''

        rendered_placeholder = RenderedPlaceholder(
            placeholder=placeholder,
            language=language,
            site_id=site_id,
            cached=use_cache,
            editable=editable,
            has_content=bool(placeholder_content),
        )

        if placeholder.pk not in self._rendered_placeholders:
            # First time this placeholder is rendered
            if not self.toolbar._cache_disabled:
                # The toolbar middleware needs to know if the response
                # is to be cached.
                # Set the _cache_disabled flag to the value of cache_placeholder
                # only if the flag is False (meaning cache is enabled).
                self.toolbar._cache_disabled = not use_cache
            self._rendered_placeholders[placeholder.pk] = rendered_placeholder

        context.pop()
        return mark_safe(toolbar_content + placeholder_content)
    def render_placeholder(self,
                           placeholder,
                           context,
                           language=None,
                           page=None,
                           editable=False,
                           use_cache=False,
                           nodelist=None,
                           width=None):
        from sekizai.helpers import Watcher
        from cms.utils.plugins import get_plugins

        language = language or self.request_language
        editable = editable and self._placeholders_are_editable

        if use_cache and not editable and placeholder.cache_placeholder:
            use_cache = self.placeholder_cache_is_enabled()
        else:
            use_cache = False

        if page:
            site_id = page.site_id
            template = page.get_template()
        else:
            site_id = get_site_id(None)
            template = None

        if use_cache:
            cached_value = self._get_cached_placeholder_content(
                placeholder=placeholder,
                site_id=site_id,
                language=language,
            )
        else:
            cached_value = None

        if cached_value is not None:
            # User has opted to use the cache
            # and there is something in the cache
            restore_sekizai_context(context, cached_value['sekizai'])
            return mark_safe(cached_value['content'])

        context.push()

        width = width or placeholder.default_width

        if width:
            context['width'] = width

        # Add extra context as defined in settings, but do not overwrite existing context variables,
        # since settings are general and database/template are specific
        # TODO this should actually happen as a plugin context processor, but these currently overwrite
        # existing context -- maybe change this order?
        for key, value in placeholder.get_extra_context(template).items():
            if key not in context:
                context[key] = value

        if use_cache:
            watcher = Watcher(context)

        plugins = get_plugins(
            request=self.request,
            placeholder=placeholder,
            template=template,
            lang=language,
        )

        if plugins:
            plugin_content = self.render_plugins(
                plugins=plugins,
                context=context,
                placeholder=placeholder,
                editable=editable,
            )
            placeholder_content = ''.join(plugin_content)
        elif nodelist:
            # should be nodelist from a template
            placeholder_content = nodelist.render(context)
        else:
            placeholder_content = ''

        if use_cache:
            content = {
                'content': placeholder_content,
                'sekizai': watcher.get_changes(),
            }
            set_placeholder_cache(
                placeholder,
                lang=language,
                site_id=site_id,
                content=content,
                request=self.request,
            )

        if editable:
            toolbar_content = self.render_editable_placeholder(
                placeholder=placeholder,
                context=context,
                language=language,
            )
        else:
            toolbar_content = ''

        rendered_placeholder = RenderedPlaceholder(
            placeholder=placeholder,
            language=language,
            site_id=site_id,
            cached=use_cache,
            editable=editable,
            has_content=bool(placeholder_content),
        )

        if placeholder.pk not in self._rendered_placeholders:
            # First time this placeholder is rendered
            if not self.toolbar._cache_disabled:
                # The toolbar middleware needs to know if the response
                # is to be cached.
                # Set the _cache_disabled flag to the value of cache_placeholder
                # only if the flag is False (meaning cache is enabled).
                self.toolbar._cache_disabled = not use_cache
            self._rendered_placeholders[placeholder.pk] = rendered_placeholder

        context.pop()
        return mark_safe(toolbar_content + placeholder_content)
Exemple #11
0
def render_placeholder(placeholder,
                       context_to_copy,
                       name_fallback="Placeholder",
                       lang=None,
                       default=None,
                       editable=True,
                       use_cache=True):
    """
    Renders plugins for a placeholder on the given page using shallow copies of the
    given context, and returns a string containing the rendered output.

    Set editable = False to disable front-end editing for this placeholder
    during rendering. This is primarily used for the "as" variant of the
    render_placeholder tag.
    """
    from cms.utils.placeholder import get_placeholder_conf, restore_sekizai_context
    from cms.utils.plugins import get_plugins
    # these are always called before all other plugin context processors
    from sekizai.helpers import Watcher

    if not placeholder:
        return
    context = copy(context_to_copy)
    context.push()
    request = context['request']
    if not hasattr(request, 'placeholders'):
        request.placeholders = []
    if placeholder.has_change_permission(
            request) or not placeholder.cache_placeholder:
        request.placeholders.append(placeholder)
    if hasattr(placeholder, 'content_cache'):
        return mark_safe(placeholder.content_cache)
    page = placeholder.page if placeholder else None
    # It's kind of duplicate of the similar call in `get_plugins`, but it's required
    # to have a valid language in this function for `get_fallback_languages` to work
    if lang:
        save_language = lang
    else:
        lang = get_language_from_request(request)
        save_language = lang

    # Prepend frontedit toolbar output if applicable
    toolbar = getattr(request, 'toolbar', None)
    if (getattr(toolbar, 'edit_mode', False)
            and getattr(toolbar, "show_toolbar", False)
            and getattr(placeholder, 'is_editable', True) and editable):
        from cms.middleware.toolbar import toolbar_plugin_processor
        processors = (toolbar_plugin_processor, )
        edit = True
    else:
        processors = None
        edit = False
    if get_cms_setting('PLACEHOLDER_CACHE') and use_cache:
        if not edit and placeholder and not hasattr(placeholder,
                                                    'cache_checked'):
            cached_value = get_placeholder_cache(placeholder, lang)
            if cached_value is not None:
                restore_sekizai_context(context, cached_value['sekizai'])
                return mark_safe(cached_value['content'])
    if page:
        template = page.template
    else:
        template = None

    plugins = [
        plugin
        for plugin in get_plugins(request, placeholder, template, lang=lang)
    ]

    # Add extra context as defined in settings, but do not overwrite existing context variables,
    # since settings are general and database/template are specific
    # TODO this should actually happen as a plugin context processor, but these currently overwrite
    # existing context -- maybe change this order?
    slot = getattr(placeholder, 'slot', None)
    if slot:
        for key, value in get_placeholder_conf("extra_context", slot, template,
                                               {}).items():
            if key not in context:
                context[key] = value
    content = []
    watcher = Watcher(context)
    content.extend(render_plugins(plugins, context, placeholder, processors))
    toolbar_content = ''

    if edit and editable:
        if not hasattr(request.toolbar, 'placeholder_list'):
            request.toolbar.placeholder_list = []
        if placeholder not in request.toolbar.placeholder_list:
            request.toolbar.placeholder_list.append(placeholder)
        toolbar_content = mark_safe(
            render_placeholder_toolbar(placeholder, context, name_fallback,
                                       save_language))
    if content:
        content = mark_safe("".join(content))
    elif default:
        # should be nodelist from a template
        content = mark_safe(default.render(context_to_copy))
    else:
        content = ''
    context['content'] = content
    context['placeholder'] = toolbar_content
    context['edit'] = edit
    result = render_to_string("cms/toolbar/content.html",
                              flatten_context(context))
    changes = watcher.get_changes()
    if placeholder and not edit and placeholder.cache_placeholder and get_cms_setting(
            'PLACEHOLDER_CACHE') and use_cache:
        set_placeholder_cache(placeholder,
                              lang,
                              content={
                                  'content': result,
                                  'sekizai': changes
                              })
    context.pop()
    return result
Exemple #12
0
def get_plugin(request, model, form_pk):
    form_obj = get_object_or_404(model, pk=form_pk)
    for plugin in get_plugins(request, form_obj.placeholder, None):
        if form_pk == plugin.pk:
            return plugin
    raise Http404()
Exemple #13
0
def render_placeholder(placeholder, context_to_copy, name_fallback="Placeholder",
                       lang=None, default=None, editable=True, use_cache=True):
    """
    Renders plugins for a placeholder on the given page using shallow copies of the
    given context, and returns a string containing the rendered output.

    Set editable = False to disable front-end editing for this placeholder
    during rendering. This is primarily used for the "as" variant of the
    render_placeholder tag.
    """
    from cms.utils.placeholder import get_placeholder_conf, restore_sekizai_context
    from cms.utils.plugins import get_plugins
    # these are always called before all other plugin context processors
    from sekizai.helpers import Watcher

    if not placeholder:
        return
    context = copy(context_to_copy)
    context.push()
    request = context['request']
    if not hasattr(request, 'placeholders'):
        request.placeholders = {}

    # Prepend frontedit toolbar output if applicable
    try:
        toolbar = getattr(request, 'toolbar', None)
    except AttributeError:
        toolbar = None

    if (toolbar and toolbar.edit_mode and toolbar.show_toolbar and
            placeholder.is_editable and editable):
        from cms.middleware.toolbar import toolbar_plugin_processor
        processors = (toolbar_plugin_processor,)
        edit = True
    else:
        processors = None
        edit = False

    if edit:
        perms = (placeholder.has_change_permission(request) or not placeholder.cache_placeholder)
        if not perms or placeholder.slot not in request.placeholders:
            request.placeholders[placeholder.slot] = (placeholder, perms)
        else:
            request.placeholders[placeholder.slot] = (
                placeholder, perms and request.placeholders[placeholder.slot][1]
            )
    else:
        request.placeholders[placeholder.slot] = (
            placeholder, False
        )
    if hasattr(placeholder, 'content_cache'):
        return mark_safe(placeholder.content_cache)
    page = placeholder.page if placeholder else None
    if page:
        site_id = page.site_id
    else:
        site_id = get_site_id(None)

    # It's kind of duplicate of the similar call in `get_plugins`, but it's required
    # to have a valid language in this function for `get_fallback_languages` to work
    if lang:
        save_language = lang
    else:
        lang = get_language_from_request(request)
        save_language = lang

    use_cache = use_cache and not request.user.is_authenticated()
    if get_cms_setting('PLACEHOLDER_CACHE') and use_cache:
        if not edit and placeholder and not hasattr(placeholder, 'cache_checked'):
            cached_value = get_placeholder_cache(placeholder, lang, site_id, request)
            if cached_value is not None:
                restore_sekizai_context(context, cached_value['sekizai'])
                return mark_safe(cached_value['content'])
    if page:
        template = page.template
    else:
        template = None

    plugins = [plugin for plugin in get_plugins(request, placeholder, template, lang=lang)]

    # Add extra context as defined in settings, but do not overwrite existing context variables,
    # since settings are general and database/template are specific
    # TODO this should actually happen as a plugin context processor, but these currently overwrite
    # existing context -- maybe change this order?
    slot = getattr(placeholder, 'slot', None)
    if slot:
        for key, value in get_placeholder_conf("extra_context", slot, template, {}).items():
            if key not in context:
                context[key] = value
    content = []
    watcher = Watcher(context)
    content.extend(render_plugins(plugins, context, placeholder, processors))
    toolbar_content = ''

    if edit and editable:
        if not hasattr(request.toolbar, 'placeholder_list'):
            request.toolbar.placeholder_list = []
        if placeholder not in request.toolbar.placeholder_list:
            request.toolbar.placeholder_list.append(placeholder)
        toolbar_content = mark_safe(render_placeholder_toolbar(placeholder, context, name_fallback, save_language))
    if content:
        content = mark_safe("".join(content))
    elif default:
        # should be nodelist from a template
        content = mark_safe(default.render(context_to_copy))
    else:
        content = ''
    context['content'] = content
    context['placeholder'] = toolbar_content
    context['edit'] = edit
    result = render_to_string("cms/toolbar/content.html", flatten_context(context))
    changes = watcher.get_changes()
    if use_cache and placeholder.cache_placeholder and get_cms_setting('PLACEHOLDER_CACHE'):
        content = {'content': result, 'sekizai': changes}
        set_placeholder_cache(placeholder, lang, site_id, content=content, request=request)
    context.pop()
    return result
def render_placeholder(
    placeholder, context_to_copy, name_fallback="Placeholder", lang=None, default=None, editable=True, use_cache=True
):
    """
    Renders plugins for a placeholder on the given page using shallow copies of the
    given context, and returns a string containing the rendered output.

    Set editable = False to disable front-end editing for this placeholder
    during rendering. This is primarily used for the "as" variant of the
    render_placeholder tag.
    """
    from cms.utils.placeholder import get_placeholder_conf, restore_sekizai_context
    from cms.utils.plugins import get_plugins

    # these are always called before all other plugin context processors
    from sekizai.helpers import Watcher

    if not placeholder:
        return
    context = copy(context_to_copy)
    context.push()
    request = context["request"]
    if not hasattr(request, "placeholders"):
        request.placeholders = []
    if placeholder.has_change_permission(request) or not placeholder.cache_placeholder:
        request.placeholders.append(placeholder)
    if hasattr(placeholder, "content_cache"):
        return mark_safe(placeholder.content_cache)
    page = placeholder.page if placeholder else None
    # It's kind of duplicate of the similar call in `get_plugins`, but it's required
    # to have a valid language in this function for `get_fallback_languages` to work
    if lang:
        save_language = lang
    else:
        lang = get_language_from_request(request)
        save_language = lang

    # Prepend frontedit toolbar output if applicable
    toolbar = getattr(request, "toolbar", None)
    if (
        getattr(toolbar, "edit_mode", False)
        and getattr(toolbar, "show_toolbar", False)
        and getattr(placeholder, "is_editable", True)
        and editable
    ):
        from cms.middleware.toolbar import toolbar_plugin_processor

        processors = (toolbar_plugin_processor,)
        edit = True
    else:
        processors = None
        edit = False
    if get_cms_setting("PLACEHOLDER_CACHE") and use_cache:
        if not edit and placeholder and not hasattr(placeholder, "cache_checked"):
            cached_value = get_placeholder_cache(placeholder, lang)
            if cached_value is not None:
                restore_sekizai_context(context, cached_value["sekizai"])
                return mark_safe(cached_value["content"])
    if page:
        template = page.template
    else:
        template = None

    plugins = [plugin for plugin in get_plugins(request, placeholder, template, lang=lang)]

    # Add extra context as defined in settings, but do not overwrite existing context variables,
    # since settings are general and database/template are specific
    # TODO this should actually happen as a plugin context processor, but these currently overwrite
    # existing context -- maybe change this order?
    slot = getattr(placeholder, "slot", None)
    if slot:
        for key, value in get_placeholder_conf("extra_context", slot, template, {}).items():
            if key not in context:
                context[key] = value
    content = []
    watcher = Watcher(context)
    content.extend(render_plugins(plugins, context, placeholder, processors))
    toolbar_content = ""

    if edit and editable:
        # TODO remove ``placeholders`` in 3.3
        if not hasattr(request.toolbar, "placeholders"):
            request.toolbar.placeholders = {}
        if not hasattr(request.toolbar, "placeholder_list"):
            request.toolbar.placeholder_list = []
        if placeholder.pk not in request.toolbar.placeholders:
            # TODO remove ``placeholders`` in 3.3
            request.toolbar.placeholders[placeholder.pk] = placeholder
            request.toolbar.placeholder_list.append(placeholder)
        toolbar_content = mark_safe(render_placeholder_toolbar(placeholder, context, name_fallback, save_language))
    if content:
        content = mark_safe("".join(content))
    elif default:
        # should be nodelist from a template
        content = mark_safe(default.render(context_to_copy))
    else:
        content = ""
    context["content"] = content
    context["placeholder"] = toolbar_content
    context["edit"] = edit
    result = render_to_string("cms/toolbar/content.html", flatten_context(context))
    changes = watcher.get_changes()
    if (
        placeholder
        and not edit
        and placeholder.cache_placeholder
        and get_cms_setting("PLACEHOLDER_CACHE")
        and use_cache
    ):
        set_placeholder_cache(placeholder, lang, content={"content": result, "sekizai": changes})
    context.pop()
    return result