1

I'm porting the functionality of an existing plugin from another CMS into Craft 3 through a custom Craft module. The functionality is:

When an option from a multi-value checkbox is checked on the "master" entry, the module will (1) create a new corresponding entry, and (2) reset the checkbox options on the "master" entry, so that no options are selected.

Research

I'm trying to be a good Craft citizen and have spent time studying the following articles. However, they either fail to mention what event they are using, or they end up using EVENT_BEFORE_SAVE_ELEMENT, or the solutions do not work with the current version of Craft (3.1.7):

Attempted Solution

protected static function creatNewEntry()
{
    Event::on(
        Elements::class,
        Elements::EVENT_AFTER_SAVE_ELEMENT,
        function(ElementEvent $event) {

            // Ignore any element that is not an entry
            if (!($event->element instanceof Entry)) {
                return;
            }

            // Ignore entries that are new because they have no id
            if ($event->isNew) {
                return;
            }

            // Ignore entries that do not belong in section id
            if ($event->element->sectionId != 5) {
                return;
            }

            // Ignore entries that are not in the primary site...
            // This is important if you have a multi-site setup
            if ($event->element->siteId != 1) {
                return;
            }

            // Fetch current entry from db. Let's call this the master entry...
            $masterEntry = Craft::$app->entries->getEntryById($event->element->id, $event->element->siteId);

            // Get values from checkbox from the master entry...
            $checkboxOptions = $masterEntry->multiCheckboxField->getOptions();

            foreach ( $checkboxOptions as $option ) {

                // What should happen when a particular checkbox value is selected?
                if ( ($option->selected == true) && ($option->value == 'example1') ) {

                    // Create new entry...
                    $newEntry = new Entry();
                    $newEntry->sectionId = $masterEntry->sectionId;
                    $newEntry->typeId = $masterEntry->typeId;
                    $newEntry->title = $masterEntry->title . 'example1';
                    $newEntry->enabled = $masterEntry->enabled;
                    $newEntry->siteId = $masterEntry->siteId;
                    $newEntry->slug = $masterEntry->slug . 'example1';

                }

                if ( ($option->selected == true) && ($option->value == 'example2') ) {

                    // Create new entry...
                    $newEntry = new Entry();
                    $newEntry->sectionId = $masterEntry->sectionId;
                    $newEntry->typeId = $masterEntry->typeId;
                    $newEntry->title = $masterEntry->title . 'example2';
                    $newEntry->enabled = $masterEntry->enabled;
                    $newEntry->siteId = $masterEntry->siteId;
                    $newEntry->slug = $masterEntry->slug . 'example2';

                }

            }

            // Handle successful / failure of new entry...
            if (isset($newEntry)) {

                $success = Craft::$app->elements->saveElement($newEntry);

                if (!$success) {
                    Craft::error('Error saving entry: '.$newEntry->title.' ('.$newEntry->id.')', __METHOD__);
                } else {
                    Craft::info('New entry saved: '.$newEntry->title.' ('.$newEntry->id.')', __METHOD__);
                }

            }

        }
    );
}

This works great! However, there is no logic in the module that resets the multi-value checkbox on the master entry.

Whilst debugging, I have tried:

  • adding $event->element->multiCheckboxField = []; on EVENT_BEFORE_SAVE_ELEMENT which resets the checkbox selected value from true to false, which is what I want! However, this does not work on EVENT_AFTER_SAVE_ELEMENT. I can't use EVENT_BEFORE_SAVE_ELEMENT because it will require a user to save twice in the CP for my module to fire off the checkbox value.
  • adding another static function, which saves the current event element however, this triggers an endless loop, which bounces between isNew' => $isNewElement on the afterSaveElement and the saveElement() in my module.
  • Thought about using a hacky JS solution in the CP - which I don't want to resort to!
1

After a few days of reflection;

I decided that resetting the checkbox values programatically on EVENT_AFTER_SAVE_ELEMENT was not really needed.

I ended up using a JS solution that unsets my checkbox values from true to false on page load. Works very well. I added my JS through an Asset Bundle, which is loaded through my module. My Asset Bundle function looks like this:

// Load asset bundle
protected static function loadAssetBundle()
{
    // Load AssetBundle
    if (Craft::$app->getRequest()->getIsCpRequest()) {

        // Don't show asset bundle on CP login
        if (Craft::$app->getUser()->getIdentity() !== NULL ) {

            Event::on(
                View::class,
                View::EVENT_BEFORE_RENDER_TEMPLATE,
                function (TemplateEvent $event) {

                    try {
                        Craft::$app->getView()->registerAssetBundle(YourModuleAsset::class);
                    } catch (InvalidConfigException $e) {
                        Craft::error(
                            'Error registering YourModuleAssetBundle - '.$e->getMessage(),
                            __METHOD__
                        );
                    }

                }
            );

        }
    }

}

The Asset Bundle JS looks like this:

// reset checkbox values after save
// Use the "Control Panel Body Classes" plugin to assign classes to <body>
if ($('body.class-set-by-cp-body-classes-plugin')[0]){
    $("input[name='fields[myCheckboxField][]']").prop('checked', false);
}

EDIT: This no longer works since upgrading to Craft 3.4. Visually, the fields are reset in the CP, but the reset values do not persist when the entry is saved

| improve this answer | |

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.