3

I'm working on an Element Action that will duplicate some fields from the primary locale, to whatever locale the user is currently in, if those fields are already empty.

Asset fields seem to work fine, but I can't find a way to duplicate Matrix fields with all their content, including their own relation fields.

So far I've got:

foreach ($criteria->find() as $element)
{
    $locale  = $criteria->locale;
    $content = $element->getContent();
    $gbr     = craft()->entries->getEntryById($element->id, 'en_gb');

    foreach ($element->getFieldLayout()->getFields() as $fieldLayoutField)
    {
        $field       = $fieldLayoutField->getField();
        $fieldHandle = $field->handle;

        if (in_array((string) $field->type, array('Assets', 'Entries', 'Categories', 'Tags')))
        {
            // only copy the relation's IDs if there's nothing there already
            if ($element->$fieldHandle->total() == 0)
            {
                $content->$fieldHandle = $gbr->$fieldHandle->ids();
            }
        }
        elseif ((string) $field->type == 'Matrix')
        {
            if ($element->$fieldHandle->total() == 0)
            {
                foreach($gbr->$fieldHandle->find() as $gbrBlock)
                {
                    // not sure what to do here to duplicate $gbrBlock,
                    // and save it to $locale with the same contents.
                }
            }
        }
    }
}

$element->setContent($content);

I've tried using craft()->matrix->getBlockById($gbrBlock->id, $locale) like you do when duplicating whole entries (they're both elements right?) but that always comes back null, so... I need to create a new MatrixBlockModel in that locale?

4

For Matrix fields, you would basically need to duplicate all of this logic (or move it to a separate function), to recreate each Matrix block.

$newBlocks = array();

foreach ($gbr->$fieldHandle->find() as $gbrBlock)
{
    $newBlock = new MatrixBlockModel();
    $newBlock->fieldId = $field->id;
    $newBlock->typeId  = $gbrBlock->getType()->id;
    $newBlock->ownerId = $element->id;
    $newBlock->locale  = $newLocale;

    $newBlockContent = $newBlock->getContent();

    foreach ($gbrBlock->getFieldLayout()->getFields() as $gbrBlockFieldLayoutField)
    {
        // same field value duplication logic...
    }

    $newBlocks[] = $newBlock;
}

$content->$fieldHandle = $newBlocks;

Unfortunately there’s just no easy way to duplicate element content at the moment. Field types each store things differently, and the way they expect their values to be formatted when saving an element may be different from how they are formatted when fetching an existing element from the DB. (This is something we’ve made much easier in Craft 3 though.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.