Jump to content

Difficulty displaying a custom button when element is InputfieldRepeater or InputfieldRepeaterMatrix


Recommended Posts


Hi everyone,

I'm having trouble correctly targeting and displaying a button within InputfieldRepeater and InputfieldRepeaterMatrix fields in ProcessWire.

My current approach involves hooking into ProcessPageEdit::buildFormContent and attempting to attach a custom button to InputfieldText and InputfieldTextarea within these repeaters.

Despite my efforts, the button is not displayed in the page that contains the reference to the Repeaters and Repeater Matrix.

Issue: The button fails to appear for InputfieldText or InputfieldTextarea within InputfieldRepeater or InputfieldRepeaterMatrix. Am I missing something in the hook or targeting logic?
Any guidance on how to ensure the button displays correctly would be greatly appreciated.

When the field is Text (InputfieldText) the button Test Button is attached/add without a problem, and I could even use appendMarkup and the button will be added (without the need of a Hook): 

Repeater Matrix and Repeaters Fields in Page

Here's my code:

public function init()
{
    parent::init();

    // Hook after the form is built to modify fields
    $this->wire->addHookAfter('ProcessPageEdit::buildFormContent', function (HookEvent $event) {
        $form = $event->return;
        $pageId = $this->input->get->int('id'); // The page being edited

        // Iterate over each form field
        foreach ($form->children as $f) {
            if ($f instanceof InputfieldRepeaterMatrix || $f instanceof InputfieldRepeater) {
                // Handle repeaters and their items
                foreach ($f->value as $item) { 
                    // Process each repeater item
                    $this->processRepeaterFields($item, $pageId);
                }
            } elseif ($f instanceof InputfieldText || $f instanceof InputfieldTextarea) {
                // Directly handle text and textarea fields
                $this->addCustomMarkupHook($f, $pageId, null, $f->name);
            }
        }
    });
}

private function processRepeaterFields($page, $pageId)
{
    foreach ($page->fields as $field) {
        $inputField = $page->getInputfield($field->name);

        if ($inputField instanceof InputfieldRepeater || $inputField instanceof InputfieldRepeaterMatrix) {
            // Process nested repeaters using recursion
            foreach ($inputField->value as $repeaterItem) {
                $this->processRepeaterFields($repeaterItem, $pageId);
            }
        } elseif ($inputField instanceof InputfieldText || $inputField instanceof InputfieldTextarea) {
            if (!empty($inputField->value)) {
                $this->addCustomMarkupHook($inputField, $pageId, $page->id, $inputField->name);
            }
        }
    }
}

private function addCustomMarkupHook($inputField, $pageId, $repeaterPageId, $inputFieldName)
{
    // Hook to modify the render output of the field
    // Is this the correct approach to add a custom button to input fields?
    $this->wire->addHookAfter('Inputfield::render', function (HookEvent $event) use ($inputField, $pageId, $repeaterPageId, $inputFieldName) {
        $field = $event->object;

        if ($field->name === $inputFieldName && !$this->isButtonAppended($event->return)) {
            $return = $event->return;
            $pageRefId = $repeaterPageId ?: $pageId;
            $buttonHtml = "<a href='/processwire/specificpage/?field={$inputFieldName}&page={$pageRefId}' data-field-name='{$inputFieldName}' data-page-id='{$pageRefId}' class='pw-panel my-action-btn'>Test Button</a>";
            $event->return = $return . $buttonHtml;
        }
    });
}

// Check if the button is already appended
private function isButtonAppended($markup)
{
    return strpos($markup, 'my-action-btn') !== false;
}


Appending a button without hooking (worked for InputfieldText/InputfieldTextarea but not Repeaters).

$f->appendMarkup("<a href='/processwire/specificpage/?field={$inputFieldName}&page={$repeaterPageId}' data-field-name='{$inputFieldName}' data-page-id='{$repeaterPageId}' class='pw-panel my-action-btn'>Test Button</a>");

Has anyone else worked with InputfieldRepeater or InputfieldRepeaterMatrix fields and successfully targeted inner fields for custom hooks? Thank you very much for any advice.

Link to comment
Share on other sites

I didn't study your post in detail, but maybe this gives you an idea:

$wire->addHookBefore('InputfieldText::render', function(HookEvent $event) {
	/** @var InputfieldText $inputfield */
	$inputfield = $event->object;
	// The Field object associated with the inputfield, so the name isn't affected by any repeater suffix
	$field = $inputfield->hasField;
	// The Page that the inputfield is in so you can check its template
	// to see if it belongs to the relevant repeater field
	$page = $inputfield->hasPage;
	if(!$field || !$page) return;

	if($field->name === 'text_1' && $page->template == 'repeater_test_repeater') {
		$inputfield->appendMarkup('hello');
	}
});

image.jpeg.4673696e597dd0e7b81142546b54c806.jpeg

  • Like 3
Link to comment
Share on other sites

Posted (edited)

Thank you @Robin S for the info shared. 

I've modified my code to rely only on the InputfieldText::render and InputfieldTextarea::render hooks.

spacer.png

Below is my code after the changes:

public function init()
    {
        parent::init();

        $this->wire->addHookBefore('InputfieldText::render', $this->addButton());
        $this->wire->addHookBefore('InputfieldTextarea::render', $this->addButton());
    }

    private function addButton()
    {
        return function (HookEvent $event) {
            $inputfield = $event->object;
            $field = $inputfield->hasField;
            $page = $inputfield->hasPage;

            if (!$field || !$page) return;

            $pageId = $page->id;

            // Do not display the button for certain fields
            if (strpos($field->name, 'some_field_name_') === 0) return;

            // Add button for the field
            $this->addButtonToField($inputfield, $field->name, $pageId);
        };
    }

    private function addButtonToField($inputfield, $fieldName, $pageId)
    {
        // Buttons displayed, but PW Panel opens in another page for Repeaters / RepeaterMatrix Page fields
        $buttonMarkup = "<a href='/processwire/setup/pageexample/?field={$fieldName}&page={$pageId}' data-field-name='{$fieldName}' data-page-id='{$pageId}' class='uk-button uk-button-default uk-button-small uk-margin-small-top pw-panel'>Action Button</a>";
        $inputfield->appendMarkup($buttonMarkup);
    }

 

Edited by Jhony Vidal
  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...