{# "Edit Element" layout template The following variables should be defined by the sub-template: - element: the source element or one of its drafts/revisions - hasRevisions: whether the element has revisions, which will determine whether the revision notes field should be displayed. - canDeleteDraft (optional): whether the current user is allowed to delete the draft (if it is one). If the current user created the draft, then it will be deletable regardless. - canUpdateSource (optional): whether the current user is allowed to update the source element (e.g. by publishing a draft or reverting the element to a prior revision) - canDuplicateSource: whether the current user is allowed to duplicate the source element - canAddAnother: whether the current user is allowed to create another source element after saving the current one - canDeleteSource: whether the current user is allowed to delete the source element - canDeleteForSite: whether the current user is allowed to delete the source element for the current site - redirectUrl: the URL that the user should be redirected to after saving the source element - addAnotherRedirectUrl: the URL that the user should be redirected to after opting to save and add another - saveSourceAction: the controller action that should be used to save the source element - duplicateSourceAction: the controller action that should be used to duplicate the source element - deleteSourceAction: the controller action that should be used to delete the source element - deleteForSiteAction: the controller action that should be used to delete the source element for the current site - saveDraftAction: the controller action that should be used to save a draft - deleteDraftAction: the controller action that should be used to delete a draft - publishDraftAction: the controller action that should be used to apply a draft onto the source element - revertSourceAction: the controller action that should be used to revert the source element to a revision - showStatusToggles: whether the “Enabled” / “Enabled” for ” fields should be added to the details pane #} {% extends '_layouts/cp' %} {% import '_includes/forms' as forms %} {% set generalConfig = craft.app.config.general %} {% set saveSourceAction = saveSourceAction ?? null %} {% set duplicateSourceAction = duplicateSourceAction ?? null %} {% set deleteSourceAction = deleteSourceAction ?? null %} {% set deleteForSiteAction = deleteForSiteAction ?? null %} {% set revertSourceAction = revertSourceAction ?? null %} {% set saveDraftAction = saveDraftAction ?? null %} {% set publishDraftAction = publishDraftAction ?? applyDraftAction ?? null %} {% set deleteDraftAction = deleteDraftAction ?? null %} {% set isDraft = element.getIsDraft() %} {% set isProvisionalDraft = element.isProvisionalDraft %} {% set isUnpublishedDraft = element.getIsUnpublishedDraft() %} {% set isRevision = element.getIsRevision() %} {% set isCurrent = not isDraft and not isRevision %} {% set isLikeCurrent = isCurrent or isProvisionalDraft or isUnpublishedDraft %} {% set allSites = craft.app.isMultiSite ? element.getSupportedSites()|map(s => s is array ? s : {siteId: s}) : [{siteId: element.siteId}] %} {% set allEditableSiteIds = craft.app.sites.getEditableSiteIds() %} {% set propSiteIds = allSites|filter(s => s.propagate ?? true)|column('siteId') %} {% set propEditableSiteIds = propSiteIds|intersect(allEditableSiteIds) %} {% set isMultiSiteElement = craft.app.isMultiSite and allSites|length > 1 %} {% set addlEditableSites = allSites|filter(s => not (s.propagate ?? true) and s.siteId in allEditableSiteIds) %} {% set canEditMultipleSites = isMultiSiteElement and (propEditableSiteIds|length > 1 or addlEditableSites|length) %} {# See if this is a new site that isn’t supported by the source element yet #} {% if isUnpublishedDraft %} {% set isNewlySupportedSite = true %} {% elseif isDraft %} {% set isNewlySupportedSite = not element.find() .id(element.getCanonicalId()) .siteId(element.siteId) .anyStatus() .exists() %} {% else %} {% set isNewlySupportedSite = false %} {% endif %} {% set previewTargets = saveDraftAction ? element.getPreviewTargets() : [] %} {% set enablePreview = previewTargets and not craft.app.request.isMobileBrowser(true) %} {% if previewTargets %} {% if isDraft and not isProvisionalDraft %} {% do craft.app.session.authorize('previewDraft:' ~ element.draftId) %} {% elseif isRevision %} {% do craft.app.session.authorize('previewRevision:' ~ element.revisionId) %} {% else %} {% do craft.app.session.authorize('previewElement:' ~ element.getCanonicalId()) %} {% endif %} {% endif %} {% set canDeleteDraft = ( isDraft and not isProvisionalDraft and ((canDeleteDraft ?? false) or element.creatorId == currentUser.id) and deleteDraftAction ) %} {% set canUpdateSource = canUpdateSource ?? false %} {% set canDuplicateSource = canDuplicateSource ?? false %} {% set canAddAnother = canAddAnother ?? false %} {% set canDeleteSource = canDeleteSource ?? false %} {% set canDeleteForSite = (canDeleteForSite ?? false) and deleteForSiteAction and isMultiSiteElement and propSiteIds|length > 1 and ((isLikeCurrent and canDeleteSource) or (isDraft and canDeleteDraft and isNewlySupportedSite)) %} {% set canEdit = canEdit ?? (canUpdateSource or canDuplicateSource or canAddAnother or saveDraftAction) %} {% set redirectUrl = redirectUrl ?? generalConfig.getPostCpLoginRedirect() %} {% set addAnotherRedirectUrl = addAnotherRedirectUrl ?? null %} {% set hashedCpEditUrl = '{cpEditUrl}'|hash %} {% if not isRevision %} {% set fullPageForm = true %} {% endif %} {# If this is an unpublished draft, then we should only show status toggles if the user actually has permission to publish changes #} {% set showStatusToggles = (showStatusToggles ?? true) and element.hasStatuses() and (not isUnpublishedDraft or canUpdateSource) %} {% if (not isDraft or isProvisionalDraft) and not canUpdateSource %} {% set saveShortcut = false %} {% elseif isCurrent and canUpdateSource %} {% set saveShortcutRedirect = '{cpEditUrl}' %} {% endif %} {% set form = element.getFieldLayout().createForm(element, isRevision or not canEdit, { registerDeltas: true, }) %} {% if tabs is not defined %} {% set tabs = form.getTabMenu() %} {% endif %} {% set settingsHtml = (block('settings') ?? '')|trim %} {# Set action button text #} {% set actionButtonLabel = 'Actions'|t('app') %} {% set formActions = [] %} {% if isLikeCurrent %} {% if canUpdateSource and saveSourceAction %} {% set formActions = formActions|push({ label: isUnpublishedDraft ? 'Create and continue editing'|t('app') : 'Save and continue editing'|t('app'), redirect: hashedCpEditUrl, shortcut: true, retainScroll: true, eventData: { autosave: false, }, }) %} {% if canAddAnother and addAnotherRedirectUrl %} {% set formActions = formActions|push({ label: isUnpublishedDraft ? 'Create and add another'|t('app') : 'Save and add another'|t('app'), action: isUnpublishedDraft ? publishDraftAction : null, redirect: addAnotherRedirectUrl|hash, shortcut: true, shift: true, eventData: { autosave: false, }, }) %} {% endif %} {% if isUnpublishedDraft %} {% set formActions = formActions|push({ label: 'Save draft'|t('app'), action: saveDraftAction, redirect: (redirectUrl ~ '#')|hash, eventData: { autosave: false, }, }) %} {% elseif canDuplicateSource and duplicateSourceAction %} {% set formActions = formActions|push({ label: 'Save as a new {type}'|t('app', { type: element.lowerDisplayName(), }), action: duplicateSourceAction, redirect: hashedCpEditUrl, }) %} {% endif %} {% endif %} {% if canDeleteForSite %} {% set formActions = formActions|push({ destructive: true, label: 'Delete {type} for this site'|t('app', { type: isUnpublishedDraft ? 'draft'|t('app') : element.lowerDisplayName(), }), action: deleteForSiteAction, redirect: (redirectUrl ~ '#')|hash, confirm: isUnpublishedDraft ? 'Are you sure you want to delete the draft for this site?'|t('app') : 'Are you sure you want to delete the {type} for this site?'|t('app', { type: element.lowerDisplayName(), }), }) %} {% endif %} {% if ( (isUnpublishedDraft and canDeleteDraft and deleteDraftAction) or (not isUnpublishedDraft and not isProvisionalDraft and canDeleteSource and deleteSourceAction) ) %} {% set formActions = formActions|push({ destructive: true, label: 'Delete {type}'|t('app', { type: isUnpublishedDraft ? 'draft'|t('app') : element.lowerDisplayName(), }), action: isUnpublishedDraft ? deleteDraftAction : deleteSourceAction, redirect: (redirectUrl ~ '#')|hash, confirm: 'Are you sure you want to delete this {type}?'|t('app', { type: isUnpublishedDraft ? 'draft'|t('app') : element.lowerDisplayName(), }), }) %} {% endif %} {% elseif isDraft %} {% if saveDraftAction %} {% set formActions = formActions|push({ label: 'Save and continue editing'|t('app'), redirect: hashedCpEditUrl, action: saveDraftAction, shortcut: true, retainScroll: true, }) %} {% endif %} {% if canDeleteDraft %} {% if canDeleteForSite %} {% set formActions = formActions|push({ destructive: true, label: 'Delete {type} for this site'|t('app', { type: 'draft'|t('app'), }), action: deleteForSiteAction, redirect: (redirectUrl ~ '#')|hash, confirm: 'Are you sure you want to delete the draft for this site?'|t('app'), }) %} {% endif %} {% set formActions = formActions|push({ destructive: true, label: 'Delete {type}'|t('app', { type: 'draft'|t('app'), }), action: deleteDraftAction, redirect: hashedCpEditUrl, confirm: 'Are you sure you want to delete this {type}?'|t('app', { type: 'draft'|t('app'), }), }) %} {% endif %} {% endif %} {% hook 'cp.elements.edit' %} {% block header %}
{{ block('pageTitle') }} {{ block('contextMenu') }}
{{ block('actionButton') }}
{% endblock %} {% block contextMenu %} {% set canHaveDrafts = not isUnpublishedDraft and saveDraftAction %} {% if isMultiSiteElement or canHaveDrafts or element.find().revisionOf(element).exists() %} {% include "_includes/revisionmenu" with { supportedSiteIds: propSiteIds, } %} {% endif %} {% if not isRevision %}
{% endif %} {% endblock %} {% block actionButton %} {% if previewTargets %}
{% if enablePreview %} {% endif %}
{% endif %} {% if isLikeCurrent %} {% if not isUnpublishedDraft and saveDraftAction %}
{{ tag('button', { type: canUpdateSource and saveSourceAction ? 'button' : 'submit', class: [ 'btn', 'formsubmit', not (canUpdateSource and saveSourceAction) ? 'submit', ]|filter, text: 'Create a draft'|t('app'), data: { action: saveDraftAction, redirect: hashedCpEditUrl, param: 'dropProvisional', value: 1, }, }) }} {% if not (canUpdateSource and saveSourceAction) %} {% if formActions is not empty %} {% include '_layouts/components/form-action-menu' %} {% endif %} {% endif %}
{% endif %} {% if canUpdateSource and saveSourceAction %}
{% if formActions is not empty %} {% include '_layouts/components/form-action-menu' %} {% endif %}
{% elseif isUnpublishedDraft %}
{% if formActions is not empty %} {% include '_layouts/components/form-action-menu' %} {% endif %}
{% endif %} {% elseif isDraft %} {% if canUpdateSource and publishDraftAction %}
{{ tag('button', { type: 'button', class: ['btn', 'secondary', 'formsubmit'], text: 'Apply draft'|t('app'), title: forms.shortcutText('S', false, true), data: { action: publishDraftAction, redirect: hashedCpEditUrl, }, }) }}
{% endif %}
{% if canDeleteDraft and formActions is not empty %} {% include '_layouts/components/form-action-menu' %} {% endif %}
{% elseif isRevision and canUpdateSource and revertSourceAction %}
{{ csrfInput() }} {{ actionInput(revertSourceAction) }} {{ redirectInput('{cpEditUrl}') }} {{ hiddenInput('revisionId', element.revisionId) }}
{% endif %} {% endblock %} {% block main %} {% if not isRevision %} {# action and redirect params #} {% if isProvisionalDraft or isUnpublishedDraft %} {% if canUpdateSource and publishDraftAction %} {{ actionInput(publishDraftAction, {id: 'action'}) }} {% endif %} {% elseif isCurrent %} {% if canUpdateSource and saveSourceAction %} {{ actionInput(saveSourceAction, {id: 'action'}) }} {% endif %} {% elseif isDraft and saveDraftAction %} {{ actionInput(saveDraftAction, {id: 'action'}) }} {% endif %} {{ redirectInput(redirectUrl) }} {# siteId param #} {% if craft.app.isMultiSite %} {{ hiddenInput('siteId', element.siteId) }} {% endif %} {# propagateAll param #} {% if isUnpublishedDraft and craft.app.request.getQueryParam('fresh') %} {{ hiddenInput('isFresh', '1') }} {% endif %} {% endif %} {{ parent() }} {% endblock %} {% block content %} {% if not isRevision %} {{ hiddenInput('sourceId', element.getCanonicalId()) }} {% else %} {{ hiddenInput('revisionId', entry.revisionId) }} {% endif %}
{{ form.render()|raw }}
{% endblock %} {% block details %} {% if notices ?? false %}
{% for notice in notices %}

{{ notice }}

{% if not loop.last %}
{% endif %} {% endfor %}
{% endif %} {% if settingsHtml %}
{{ settingsHtml|raw }}
{% endif %} {% if showStatusToggles and isMultiSiteElement %}
{{ forms.lightswitchField({ status: element.getAttributeStatus('enabled'), label: 'Enabled for {site}'|t('app', { site: element.site.name|t('site')|e }) ~ (canEditMultipleSites ? tag('button', { type: 'button', id: 'expand-status-btn', class: ['btn'], data: { icon: 'ellipsis', }, })), id: "enabledForSite-#{element.siteId}", name: "enabledForSite[#{element.siteId}]", on: element.enabled and element.getEnabledForSite(), disabled: isRevision, }) }}
{% endif %}
{% block meta %} {% set metaElement = isProvisionalDraft ? element.getCanonical(true) : element %} {% if element.hasStatuses() %} {% if isUnpublishedDraft %} {% set statusColor = 'white' %} {% set statusLabel = 'Draft'|t('app') %} {% else %} {% set status = element.getStatus() %} {% set statusDef = element.statuses()[status] ?? null %} {% set statusColor = statusDef.color ?? status %} {% set statusLabel = statusDef.label ?? statusDef ?? status|ucfirst %} {% endif %}
{{ 'Status'|t('app') }}
{% if isUnpublishedDraft %} {% else %} {% endif %} {{ statusLabel }}
{% endif %}
{{ "Created at"|t('app') }}
{{ metaElement.dateCreated|datetime('short') }}
{{ "Updated at"|t('app') }}
{{ metaElement.dateUpdated|datetime('short') }}
{% if isRevision %} {% set revisionNotes = element.revisionNotes %} {% elseif isLikeCurrent and metaElement.currentRevision %} {% set revisionNotes = metaElement.currentRevision.revisionNotes %} {% else %} {% set revisionNotes = null %} {% endif %} {% if revisionNotes %}
{{ "Notes"|t('app') }}
{{ revisionNotes }}
{% endif %} {% endblock %}
{% if (isLikeCurrent and (hasRevisions ?? false)) or isDraft %} {{ forms.textarea({ id: 'notes', class: ['nicetext'], name: 'notes', placeholder: 'Notes about your changes'|t('app'), value: isCurrent ? (notes ?? null) : element.draftNotes, inputAttributes: { aria: { label: 'Notes about your changes'|t('app'), }, }, }) }} {% endif %} {% endblock %} {% block settings %} {% if showStatusToggles and not isMultiSiteElement %} {{ forms.lightswitchField({ status: element.getAttributeStatus('enabled'), label: 'Enabled'|t('app'), id: 'enabled', name: 'enabled', on: element.enabled, disabled: isRevision, }) }} {% endif %} {% endblock %} {# Only fetch the element’s per-site statuses if it’s enabled globally. Otherwise they don’t have any effect #} {% if canEditMultipleSites and element.enabled and element.id %} {% set siteStatusesQuery = element.find() .select(['elements_sites.siteId', 'elements_sites.enabled']) .id(element.id) .siteId(propEditableSiteIds) .anyStatus() .asArray() %} {% if isProvisionalDraft %} {% do siteStatusesQuery.provisionalDrafts() %} {% elseif isDraft %} {% do siteStatusesQuery.drafts() %} {% elseif isRevision %} {% do siteStatusesQuery.revisions() %} {% endif %} {% set siteStatuses = siteStatusesQuery .pairs()|map(s => s ? true : false) %} {% elseif canEditMultipleSites %} {% set siteStatusValues = {} %} {# If the element isn't saved yet, assume other sites will share its current status #} {% set defaultStatus = element.id ? false : (element.enabled and element.enabledForSite) %} {% for siteId in propEditableSiteIds %} {% set siteStatusValues = siteStatusValues|merge([defaultStatus]) %} {% endfor %} {% set siteStatuses = combine(propEditableSiteIds, siteStatusValues) %} {% else %} {% set siteStatuses = { ("#{element.siteId}"): element.enabled ? true : false } %} {% endif %} {% set settings = { elementType: className(element), sourceId: element.getCanonicalId(), siteId: element.siteId, isUnpublishedDraft: isUnpublishedDraft, enabled: element.enabled ? true : false, enabledForSite: element.enabled and element.getEnabledForSite(), isLive: isCurrent and element.enabled and element.getEnabledForSite() and element.getRoute(), isProvisionalDraft: isProvisionalDraft, siteStatuses: siteStatuses, addlSites: addlEditableSites|values, cpEditUrl: element.cpEditUrl, draftId: element.draftId, revisionId: element.revisionId, draftName: isDraft ? element.draftName : null, canEditMultipleSites: canEditMultipleSites, canUpdateSource: canUpdateSource, saveDraftAction: saveDraftAction, deleteDraftAction: deleteDraftAction, publishDraftAction: publishDraftAction, hashedCpEditUrl: hashedCpEditUrl, hashedAddAnotherRedirectUrl: addAnotherRedirectUrl ? addAnotherRedirectUrl|hash : null, enablePreview: enablePreview, previewTargets: previewTargets, previewToken: previewTargets ? craft.app.security.generateRandomString() : null, siteToken: (not craft.app.isLive or not element.getSite().enabled) ? element.siteId|hash, } %} {% js %} window.draftEditor = new Craft.DraftEditor({{ settings|json_encode|raw }}); {% endjs %}