def _get_placeholder(current_page, page, context, name): placeholder_cache = getattr(current_page, '_tmp_placeholders_cache', {}) if page.pk in placeholder_cache: placeholder = placeholder_cache[page.pk].get(name, None) if placeholder: return placeholder placeholder_cache[page.pk] = {} placeholders = page.rescan_placeholders().values() fetch_placeholders = [] request = context['request'] if not get_cms_setting('PLACEHOLDER_CACHE') or (hasattr(request, 'toolbar') and request.toolbar.edit_mode): fetch_placeholders = placeholders else: for placeholder in placeholders: cached_value = get_placeholder_cache(placeholder, get_language()) if cached_value is not None: restore_sekizai_context(context, cached_value['sekizai']) placeholder.content_cache = cached_value['content'] else: fetch_placeholders.append(placeholder) placeholder.cache_checked = True if fetch_placeholders: assign_plugins(context['request'], fetch_placeholders, page.get_template(), get_language()) for placeholder in placeholders: placeholder_cache[page.pk][placeholder.slot] = placeholder placeholder.page = page current_page._tmp_placeholders_cache = placeholder_cache placeholder = placeholder_cache[page.pk].get(name, None) if page.application_urls and not placeholder: raise PlaceholderNotFound( '"%s" placeholder not found in an apphook application. Please use a static placeholder instead.' % name) return placeholder
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_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)
def _get_placeholder(current_page, page, context, name): from django.core.cache import cache placeholder_cache = getattr(current_page, '_tmp_placeholders_cache', {}) if page.pk in placeholder_cache: placeholder = placeholder_cache[page.pk].get(name, None) if placeholder: return placeholder placeholder_cache[page.pk] = {} placeholders = page.rescan_placeholders().values() fetch_placeholders = [] request = context['request'] if not get_cms_setting('PLACEHOLDER_CACHE') or (hasattr(request, 'toolbar') and request.toolbar.edit_mode): fetch_placeholders = placeholders else: for placeholder in placeholders: 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']) placeholder.content_cache = cached_value['content'] else: fetch_placeholders.append(placeholder) placeholder.cache_checked = True if fetch_placeholders: assign_plugins(context['request'], fetch_placeholders, page.get_template(), get_language()) for placeholder in placeholders: placeholder_cache[page.pk][placeholder.slot] = placeholder placeholder.page = page current_page._tmp_placeholders_cache = placeholder_cache placeholder = placeholder_cache[page.pk].get(name, None) if page.application_urls and not placeholder: raise PlaceholderNotFound( '"%s" placeholder not found in an apphook application. Please use a static placeholder instead.' % name) return placeholder
def _show_placeholder_for_page(context, placeholder_name, page_lookup, lang=None, site=None, cache_result=True): """ Shows the content of a page with a placeholder name and given lookup arguments in the given language. This is useful if you want to have some more or less static content that is shared among many pages, such as a footer. See _get_page_by_untyped_arg() for detailed information on the allowed types and their interpretation for the page_lookup argument. """ from django.core.cache import cache validate_placeholder_name(placeholder_name) request = context.get('request', False) site_id = get_site_id(site) if not request: return {'content': ''} if lang is None: lang = get_language_from_request(request) if cache_result: base_key = _get_cache_key('_show_placeholder_for_page', page_lookup, lang, site_id) cache_key = _clean_key('%s_placeholder:%s' % (base_key, placeholder_name)) cached_value = cache.get(cache_key) if cached_value: restore_sekizai_context(context, cached_value['sekizai']) return {'content': mark_safe(cached_value['content'])} page = _get_page_by_untyped_arg(page_lookup, request, site_id) if not page: return {'content': ''} try: placeholder = page.placeholders.get(slot=placeholder_name) except PlaceholderModel.DoesNotExist: if settings.DEBUG: raise return {'content': ''} watcher = Watcher(context) content = render_placeholder(placeholder, context, placeholder_name, use_cache=cache_result) changes = watcher.get_changes() if cache_result: cache.set(cache_key, { 'content': content, 'sekizai': changes }, get_cms_setting('CACHE_DURATIONS')['content']) if content: return {'content': mark_safe(content)} return {'content': ''}
def _show_placeholder_for_page(context, placeholder_name, page_lookup, lang=None, site=None, cache_result=True): """ Shows the content of a page with a placeholder name and given lookup arguments in the given language. This is useful if you want to have some more or less static content that is shared among many pages, such as a footer. See _get_page_by_untyped_arg() for detailed information on the allowed types and their interpretation for the page_lookup argument. """ validate_placeholder_name(placeholder_name) if DJANGO_1_7: request = context.get('request', False) else: request = context.request site_id = get_site_id(site) if not request: return {'content': ''} if lang is None: lang = get_language_from_request(request) if cache_result: cached_value = get_placeholder_page_cache(page_lookup, lang, site_id, placeholder_name) if cached_value: restore_sekizai_context(context, cached_value['sekizai']) return {'content': mark_safe(cached_value['content'])} page = _get_page_by_untyped_arg(page_lookup, request, site_id) if not page: return {'content': ''} try: placeholder = page.placeholders.get(slot=placeholder_name) except PlaceholderModel.DoesNotExist: if settings.DEBUG: raise return {'content': ''} watcher = Watcher(context) content = render_placeholder(placeholder, context, placeholder_name, use_cache=cache_result) changes = watcher.get_changes() if cache_result: set_placeholder_page_cache(page_lookup, lang, site_id, placeholder_name, {'content': content, 'sekizai': changes}) if content: return {'content': mark_safe(content)} return {'content': ''}
def _show_placeholder_for_page(context, placeholder_name, page_lookup, lang=None, site=None, cache_result=True): """ Shows the content of a page with a placeholder name and given lookup arguments in the given language. This is useful if you want to have some more or less static content that is shared among many pages, such as a footer. See _get_page_by_untyped_arg() for detailed information on the allowed types and their interpretation for the page_lookup argument. """ validate_placeholder_name(placeholder_name) request = context.get('request', False) site_id = get_site_id(site) if not request: return {'content': ''} if lang is None: lang = get_language_from_request(request) page = _get_page_by_untyped_arg(page_lookup, request, site_id) if not page: return {'content': ''} try: placeholder = page.placeholders.get(slot=placeholder_name) except PlaceholderModel.DoesNotExist: if settings.DEBUG: raise return {'content': ''} if cache_result: cached_value = get_placeholder_cache(placeholder, lang, site_id, request) if cached_value: restore_sekizai_context(context, cached_value['sekizai']) return {'content': mark_safe(cached_value['content'])} watcher = Watcher(context) content = render_placeholder(placeholder, context, placeholder_name, lang=lang, use_cache=cache_result) changes = watcher.get_changes() edit_mode = hasattr(request, 'toolbar') and getattr(request.toolbar, 'edit_mode', False) if not edit_mode and placeholder and placeholder.cache_placeholder and get_cms_setting('PLACEHOLDER_CACHE') and cache_result: # noqa set_placeholder_cache(placeholder, lang, site_id, {'content': content, 'sekizai': changes}, request) if content: return {'content': mark_safe(content)} return {'content': ''}
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(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
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