Selectable Assets Condition - Add variables like in Routes and Asset Location #12026
-
Is there any way to use variables from the entry like {slug} in the Selectable Assets Condition section of an Asset field? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
Not currently. How would you envision it working exactly? |
Beta Was this translation helpful? Give feedback.
-
@brandonkelly You know how in Routes and Asset Location fields you can enter a custom path, but also have access to vars like {slug} based on the context? I'd envision it working the same way here. When you're creating a condition, you could use vars available in the current context to limit what assets are displayed in the asset browser. The use-case for us is we have a section with ~20,000 assets spread across ~10,000 entries. We tried putting each entry's files in its own dir (using the dynamic asset path mentioned above) but trying to render ~10,000 dirs borked the asset browser. The files all follow a naming convention, so we could use data in a given entry to limit what assets are selectable from within that entry. I know it's pretty niche, but it doesn't hurt to ask right? |
Beta Was this translation helpful? Give feedback.
-
Conditions aren’t inherently aware of their context so this wouldn’t really be possible. However you can supply your own custom condition rule from a module, which keeps its own reference to the entry being edited, and filters the assets accordingly. We’re still working on condition documentation, but here’s what the rule would look like: namespace mymodulenamespace;
use Craft;
use craft\base\conditions\BaseConditionRule;
use craft\base\ElementInterface;
use craft\elements\conditions\ElementConditionRuleInterface;
use craft\elements\db\AssetQuery;
use craft\elements\db\ElementQueryInterface;
class MyAssetConditionRule extends BaseConditionRule implements ElementConditionRuleInterface
{
public ?int $editedElementId = null;
public function getConfig(): array
{
$config = parent::getConfig();
if (Craft::$app->controller instanceof \craft\controllers\ElementsController) {
$config['editedElementId'] = Craft::$app->controller->element->id ?? null;
}
return $config;
}
public function getLabel(): string
{
return 'Limit based on the entry';
}
public function getExclusiveQueryParams(): array
{
return [];
}
/**
* @inheritdoc
*/
public function modifyQuery(ElementQueryInterface $query): void
{
if ($this->editedElementId) {
$element = Craft::$app->elements->getElementById($this->editedElementId);
if ($element) {
// Find the folder associated with this entry
$folder = Craft::$app->assets->findFolder(['path' => $element->slug]);
if ($folder) {
// Limit the query to only that folder and its subfolders
/** @var AssetQuery $query */
$query->folderId($folder->id)->includeSubfolders();
}
}
}
}
/**
* @inheritdoc
*/
public function matchElement(ElementInterface $element): bool
{
// This condition shouldn't be used on individual assets
return false;
}
} Register the condition rule for use in asset conditions like so: use craft\elements\conditions\assets\AssetCondition;
use craft\events\RegisterConditionRuleTypesEvent;
use yii\base\Event;
Event::on(
AssetCondition::class,
AssetCondition::EVENT_REGISTER_CONDITION_RULE_TYPES,
function(RegisterConditionRuleTypesEvent $event) {
$event->conditionRuleTypes[] = MyAssetConditionRule::class;
}
); Then from your Assets field, you can select your new condition rule in the Selectable Assets Condition. (Note that this will require Craft 4.3+, as that’s when This won’t solve the performance problem though, which comes from rendering the folder tree. We’re brainstorming ways to improve that, but it’s likely going to require a breaking change so more of a 5.0 thing. In the meantime, you could hook into the use craft\elements\Asset;
use craft\events\RegisterElementSourcesEvent;
use yii\base\Event;
Event::on(
Asset::class,
Asset::EVENT_REGISTER_SOURCES,
function(RegisterElementSourcesEvent $event) {
$volume = Craft::$app->volumes->getVolumeByHandle('myVolumeHandle');
if ($volume) {
// Replace the stock source definition for the volume with a custom
// one that doesn’t worry about subfolders
foreach ($event->sources as $i => $source) {
if ($source['key'] === "volume:$volume->uid") {
$event->sources[$i] = [
'key' => 'custom-volume',
'label' => $volume->name,
'hasThumbs' => true,
'criteria' => ['volumeId' => $volume->id],
'defaultSort' => ['dateCreated', 'desc'],
];
}
}
}
}
); |
Beta Was this translation helpful? Give feedback.
Conditions aren’t inherently aware of their context so this wouldn’t really be possible. However you can supply your own custom condition rule from a module, which keeps its own reference to the entry being edited, and filters the assets accordingly.
We’re still working on condition documentation, but here’s what the rule would look like: