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):
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.