Skip to content

Commit

Permalink
Allow single-site entries in multi-site sections
Browse files Browse the repository at this point in the history
Resolves #2330
  • Loading branch information
brandonkelly committed Jan 23, 2018
1 parent 1720984 commit a3cc52f
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 35 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG-v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
### Added
- Asset editor HUDs now show image previews. ([#837](https://github.com/craftcms/cms/issues/837))
- It’s now possible to access the Image Editor from Assets fields and asset indexes by double-clicking on an asset and clicking on the image preview within the HUD that opens up. ([#1324](https://github.com/craftcms/cms/issues/1324))
- Added the “Propagate entries across all enabled sites?” section setting. If disabled, entries will only be associated with the site they were created on. ([#2330](https://github.com/craftcms/cms/issues/2330))
- Added the `alias()` Twig function, which translates a path/URL alias (`@someAlias/sub/path`) into an actual path/URL. ([#2327](https://github.com/craftcms/cms/issues/2327))
- Added `craft\elements\Asset::getSupportsImageEditor()`.
- Added `craft\elements\db\ElementQuery::inReverse()`, which can be used to reverse the order that elements are returned in.
- Added `craft\events\GetAssetThumbUrlEvent::width` and `height`, which should be used instead of `size`.
- Added `craft\helpers\Assets::filename2Title()`.
- Added `craft\models\CategoryGroup_SiteSettings::getSite()`.
- Added `craft\models\Section::propagateEntries`.
- Added `craft\models\Section_SiteSettings::getSite()`.
- Added the `cp.categories.edit.content` template hook to the `categories/_edit.html` template.
- Added the `cp.entries.edit.content` template hook to the `entries/_edit.html` template.
Expand Down
2 changes: 1 addition & 1 deletion src/config/app/main.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
'id' => 'CraftCMS',
'name' => 'Craft CMS',
'version' => '3.0.0-RC6',
'schemaVersion' => '3.0.78',
'schemaVersion' => '3.0.79',
'minVersionRequired' => '2.6.2788',
'basePath' => dirname(__DIR__, 2), // Defines the @app alias
'runtimePath' => '@storage/runtime', // Defines the @runtime alias
Expand Down
8 changes: 7 additions & 1 deletion src/controllers/EntriesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,13 @@ public function actionEditEntry(string $sectionHandle, int $entryId = null, int
// ---------------------------------------------------------------------

// Page title w/ revision label
if ($variables['showSites'] = (Craft::$app->getIsMultiSite() && count($section->getSiteSettings()) > 1)) {
$variables['showSites'] = (
Craft::$app->getIsMultiSite() &&
count($section->getSiteSettings()) > 1 &&
($section->propagateEntries || $entry->id === null)
);

if ($variables['showSites']) {
$variables['revisionLabel'] = Craft::t('site', $entry->getSite()->name).'';
} else {
$variables['revisionLabel'] = '';
Expand Down
1 change: 1 addition & 0 deletions src/controllers/SectionsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ public function actionSaveSection()
$section->handle = $request->getBodyParam('handle');
$section->type = $request->getBodyParam('type');
$section->enableVersioning = $request->getBodyParam('enableVersioning', true);
$section->propagateEntries = $request->getBodyParam('propagateEntries', true);

if ($section->type === Section::TYPE_STRUCTURE) {
$section->maxLevels = $request->getBodyParam('maxLevels');
Expand Down
13 changes: 8 additions & 5 deletions src/elements/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -557,13 +557,16 @@ public function rules()
*/
public function getSupportedSites(): array
{
$section = $this->getSection();
$sites = [];

foreach ($this->getSection()->getSiteSettings() as $siteSettings) {
$sites[] = [
'siteId' => $siteSettings->siteId,
'enabledByDefault' => $siteSettings->enabledByDefault
];
foreach ($section->getSiteSettings() as $siteSettings) {
if ($section->propagateEntries || $siteSettings->siteId == $this->siteId) {
$sites[] = [
'siteId' => $siteSettings->siteId,
'enabledByDefault' => $siteSettings->enabledByDefault
];
}
}

return $sites;
Expand Down
1 change: 1 addition & 0 deletions src/migrations/Install.php
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ protected function createTables()
'handle' => $this->string()->notNull(),
'type' => $this->enum('type', ['single', 'channel', 'structure'])->notNull()->defaultValue('channel'),
'enableVersioning' => $this->boolean()->defaultValue(false)->notNull(),
'propagateEntries' => $this->boolean()->defaultValue(true)->notNull(),
'dateCreated' => $this->dateTime()->notNull(),
'dateUpdated' => $this->dateTime()->notNull(),
'uid' => $this->uid(),
Expand Down
29 changes: 29 additions & 0 deletions src/migrations/m180122_213433_propagate_entries_setting.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace craft\migrations;

use Craft;
use craft\db\Migration;

/**
* m180122_213433_propagate_entries_setting migration.
*/
class m180122_213433_propagate_entries_setting extends Migration
{
/**
* @inheritdoc
*/
public function safeUp()
{
$this->addColumn('{{%sections}}', 'propagateEntries', $this->boolean()->defaultValue(true)->notNull());
}

/**
* @inheritdoc
*/
public function safeDown()
{
echo "m180122_213433_propagate_entries_setting cannot be reverted.\n";
return false;
}
}
5 changes: 5 additions & 0 deletions src/models/Section.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ class Section extends Model
*/
public $enableVersioning = true;

/**
* @var bool Propagate entries
*/
public $propagateEntries = true;

/**
* @var Section_SiteSettings[]|null
*/
Expand Down
1 change: 1 addition & 0 deletions src/records/Section.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* @property string $handle Handle
* @property string $type Type
* @property bool $enableVersioning Enable versioning
* @property bool $propagateEntries Propagate entries
* @property Section_SiteSettings[] $siteSettings Site settings
* @property Structure $structure Structure
*
Expand Down
107 changes: 79 additions & 28 deletions src/services/Sections.php
Original file line number Diff line number Diff line change
Expand Up @@ -392,17 +392,23 @@ public function saveSection(Section $section, bool $runValidation = true): bool
'handle',
'type',
'enableVersioning',
'propagateEntries',
]));
} else {
$sectionRecord = new SectionRecord();
}

// Main section settings
if ($section->type !== Section::TYPE_CHANNEL) {
$section->propagateEntries = false;
}

This comment has been minimized.

Copy link
@mattcdavis1

mattcdavis1 Jan 23, 2018

I'm thinking we still need to be able to propagate a single in the admin/settings/sections context or there could only be one of any given single accross all sites as opposed to each site having it's own "Home" or "About" page. I've implemented a temporary workaround here by commenting out $section->propagateEntries = false; above and adding the below code in Sections.php so that each of my sites can have it's own set of singles.

public function saveElement(ElementInterface $element, bool $runValidation = true, bool $propagate = true): bool
{
    if ($element instanceof Entry) {
        $segment1 = Craft::$app->request->getSegment(1);
        $type = $element->getSection()->type ?? null;

        if ($type === 'single' && $segment1 == 'entries') {
            $propagate = false;
        }
    }

    return parent::saveElement($element, $runValidation, $propagate);
}

Otherwise, for me using the current latest on development, i'm unable to create a single on more than one site (also i'm manually setting the propagate flag in the DB so it will propagate in the settings context).

This comment has been minimized.

Copy link
@brandonkelly

brandonkelly Jan 24, 2018

Author Member

I don’t think that’s right. You have two options with singles:

  • create one Single section that is enabled for multiple sites
  • create multiple singles, each only enabled for a single site

Whatever you want to do with Singles and multi-site, one of those two options should cover it.

This comment has been minimized.

Copy link
@mattcdavis1

mattcdavis1 Jan 24, 2018

The code above is definitely just meant to be a temporary workaround but the underlying issue is that the options mentioned above are not working. I cannot currently do either of the 2 things you mentioned:

  • create one Single section that is enabled for multiple sites. I can't do this right now
  • create multiple singles, each only enabled for a single site. I can't do this either

Here's some screenshots to illustrate what i'm seeing (with my hack disabled).

  1. Create "Foo Entry" enabled on all sites. Screenshot
  2. Attempt to view/edit "Foo Entry" on all sites:

This comment has been minimized.

Copy link
@mattcdavis1

mattcdavis1 Jan 24, 2018

Think i accidentally saved the above comment prematurely. Updated with details.

This comment has been minimized.

Copy link
@fvaldes33

fvaldes33 Jan 31, 2018

Could we also have this functionality added for Structures? It is currently only available for channels...

This comment has been minimized.

Copy link
@brandonkelly

brandonkelly Jan 31, 2018

Author Member

@fvaldes33 Adding to Structures would be much more involved, as each site would need to have its own structure ID. Not saying we can’t, but would need to happen after 3.0. Can you post a new FR for it? https://github.com/craftcms/cms/issues

This comment has been minimized.

Copy link
@brandonkelly

brandonkelly Feb 1, 2018

Author Member

@fvaldes33 Nevermind, @Rias500 beat you to it: #2386

/** @var SectionRecord $sectionRecord */
$sectionRecord->name = $section->name;
$sectionRecord->handle = $section->handle;
$sectionRecord->type = $section->type;
$sectionRecord->enableVersioning = (bool)$section->enableVersioning;
$sectionRecord->propagateEntries = (bool)$section->propagateEntries;

// Get the site settings
$allSiteSettings = $section->getSiteSettings();
Expand Down Expand Up @@ -553,21 +559,42 @@ public function saveSection(Section $section, bool $runValidation = true): bool
// -----------------------------------------------------------------

if (!$isNewSection) {
// Find a site that the section was already enabled in, and still is
$oldSiteIds = array_keys($allOldSiteSettingsRecords);
$newSiteIds = array_keys($section->getSiteSettings());
$persistentSiteIds = array_intersect($newSiteIds, $oldSiteIds);

Craft::$app->getQueue()->push(new ResaveElements([
'description' => Craft::t('app', 'Resaving {section} entries', ['section' => $section->name]),
'elementType' => Entry::class,
'criteria' => [
'siteId' => $persistentSiteIds[0],
'sectionId' => $section->id,
'status' => null,
'enabledForSite' => false,
]
]));
if ($section->propagateEntries) {
// Find a site that the section was already enabled in, and still is
$oldSiteIds = array_keys($allOldSiteSettingsRecords);
$newSiteIds = array_keys($allSiteSettings);
$persistentSiteIds = array_intersect($newSiteIds, $oldSiteIds);

Craft::$app->getQueue()->push(new ResaveElements([
'description' => Craft::t('app', 'Resaving {section} entries', [
'section' => $section->name,
]),
'elementType' => Entry::class,
'criteria' => [
'siteId' => $persistentSiteIds[0],
'sectionId' => $section->id,
'status' => null,
'enabledForSite' => false,
]
]));
} else {
// Resave entries for each site
foreach ($allSiteSettings as $siteId => $siteSettings) {
Craft::$app->getQueue()->push(new ResaveElements([
'description' => Craft::t('app', 'Resaving {section} entries ({site})', [
'section' => $section->name,
'site' => $siteSettings->getSite()->name,
]),
'elementType' => Entry::class,
'criteria' => [
'siteId' => $siteId,
'sectionId' => $section->id,
'status' => null,
'enabledForSite' => false,
]
]));
}
}
}

$transaction->commit();
Expand Down Expand Up @@ -879,19 +906,42 @@ public function saveEntryType(EntryType $entryType, bool $runValidation = true):
if (!$isNewEntryType) {
// Re-save the entries of this type
$section = $entryType->getSection();
$siteIds = array_keys($section->getSiteSettings());

Craft::$app->getQueue()->push(new ResaveElements([
'description' => Craft::t('app', 'Resaving {type} entries', ['type' => $entryType->name]),
'elementType' => Entry::class,
'criteria' => [
'siteId' => $siteIds[0],
'sectionId' => $section->id,
'typeId' => $entryType->id,
'status' => null,
'enabledForSite' => false,
]
]));
$allSiteSettings = $section->getSiteSettings();

if ($section->propagateEntries) {
$siteIds = array_keys($allSiteSettings);

Craft::$app->getQueue()->push(new ResaveElements([
'description' => Craft::t('app', 'Resaving {type} entries', [
'type' => $entryType->name,
]),
'elementType' => Entry::class,
'criteria' => [
'siteId' => $siteIds[0],
'sectionId' => $section->id,
'typeId' => $entryType->id,
'status' => null,
'enabledForSite' => false,
]
]));
} else {
foreach ($allSiteSettings as $siteId => $siteSettings) {
Craft::$app->getQueue()->push(new ResaveElements([
'description' => Craft::t('app', 'Resaving {type} entries ({site})', [
'type' => $entryType->name,
'site' => $siteSettings->getSite()->name,
]),
'elementType' => Entry::class,
'criteria' => [
'siteId' => $siteId,
'sectionId' => $section->id,
'typeId' => $entryType->id,
'status' => null,
'enabledForSite' => false,
]
]));
}
}
}

return true;
Expand Down Expand Up @@ -1026,6 +1076,7 @@ private function _createSectionQuery(): Query
'sections.handle',
'sections.type',
'sections.enableVersioning',
'sections.propagateEntries',
'structures.maxLevels',
])
->leftJoin('{{%structures}} structures', '[[structures.id]] = [[sections.structureId]]')
Expand Down
13 changes: 13 additions & 0 deletions src/templates/settings/sections/_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,19 @@
errors: siteErrors|unique
}) }}

{% if craft.app.getIsMultiSite() %}
<div class="type-channel {% if section.type != 'channel' %}hidden{% endif %}">
{{ forms.checkboxField({
label: 'Propagate entries across all enabled sites?'|t('app'),
instructions: 'Whether entries should be propagated across all the sites the section is enabled in. If this is disabled, each entry will only belong to the site it was created in.'|t('app'),
id: 'propagateEntries',
name: 'propagateEntries',
checked: section.propagateEntries,
warning: section.id and section.propagateEntries ? 'Changing this may result in data loss.'|t('app')
}) }}
</div>
{% endif %}

<div class="type-structure {% if section.type != 'structure' %}hidden{% endif %}">
{{ forms.textField({
label: "Max Levels"|t('app'),
Expand Down

0 comments on commit a3cc52f

Please sign in to comment.