Jump to content

Disable a field on the profile edit form


schwarzdesign
 Share

Recommended Posts

I'm trying to disable a specific field only when it is displayed on a user's profile edit page. I have worked out the following solution, but it's shaky and I'm looking for a better approach:

// disable the member type field when members edit their own profile
wire()->addHookBefore('InputfieldPage::render', function (HookEvent $e) {
    $inputfield = $e->object;
    $field = $inputfield->hasField;
    $user = $inputfield->hasPage;
    $process = wire('process');

    // only handle the u_type field
    if ($field->name !== 'u_type') return;
    // only for profile edits
    if (!($process instanceof ProcessProfile)) return;
    // only for regular members without additional access
    if ($user->isSuperuser() || $user->hasRole('editor')) return;

    // get the inputfield the InputfieldPage is delegated to (InputfieldRadios)
    $delegatedInputfield = $inputfield->getInputfield();
    // get all available options
    $optionKeys = array_keys($inputfield->getInputfield()->getOptions());
    // build an array with option id => attributes maps (this is the format expected by InputfieldRadios)
    $optionAttributes = array_combine(
        $optionKeys,
        array_map(fn($o) => ['disabled' => 'disabled'], $optionKeys)
    );
    // add the attributes to the delegated inputfield to disable all options
    $delegatedInputfield->addOptionAttributes($optionAttributes);
});

What bugs me about this:

  • Seems overly complicated, isn't there a better way than going through the delegated inputfield and then setting the attribute manually for all options? Like a global disabled switch on InputfieldPage?
  • The hook is dependent on the type of delegated inputfield and might break if it's switched to something else.
  • This only sets the HTML disabled attribute, so it's easy to bypass. Of course I could add backend validation separately, but I would prefer a "unified" solution. Though for my use-case the backend validation is not that important, it's more about UX.

By the way, just setting the field to hidden does not work in this case, because a couple of other fields have show_if dependencies on the field I'm trying to disable, and those don't seem to work when the field is not rendered at all.

Any of you know a better approach?

Thanks!

Link to comment
Share on other sites

On 2/11/2021 at 5:31 AM, schwarzdesign said:

By the way, just setting the field to hidden does not work in this case, because a couple of other fields have show_if dependencies on the field I'm trying to disable, and those don't seem to work when the field is not rendered at all.

This is the crux of the issue. If the user shouldn't be able to edit a field then you don't want it included in the ProcessProfile form, but as you say this causes issues with inputfield dependencies.

My suggestion is:

1. Only include editable fields in ProcessProfile.
2. Remove the showIf condition when the dependent fields appear in ProcessProfile.
3. Implement the same showIf logic to determine which fields are editable in ProcessProfile.

Example...

In this case I have fields text_1, text_2 and text_3 in the user template. The text_2 and text_3 fields have the showIf condition "text_1=foo". But I don't want the user to be able to edit text_1 in ProcessProfile so I disable that field in the ProcessProfile module settings:

2021-02-13_203716.png.17e19a39fd6533ab14e7e2e0ee547bfb.png

In /site/ready.php:

$wire->addHookBefore('ProcessProfile::execute', function(HookEvent $event) {
	/** @var ProcessProfile $pp */
	$pp = $event->object;
	// The fields that have a showIf dependency on a field not editable in ProcessProfile
	$dependent_fields = ['text_2', 'text_3'];

	// If dependency condition not met, remove dependent fields from the ProcessProfile editable fields
	if($event->wire()->user->text_1 !== 'foo') {
		$pp->profileFields = array_diff($pp->profileFields, $dependent_fields);
	}

	// Remove showIf condition from dependent fields
	$event->wire()->addHookAfter('Field::getInputfield', function(HookEvent $event) use ($dependent_fields) {
		$inputfield = $event->return;
		if(!in_array($inputfield->name, $dependent_fields)) return;
		$inputfield->showIf = '';
	});
});

 

  • Like 1
Link to comment
Share on other sites

@Robin S Good idea, thanks! The only problem I have with that solution is that it's hardcoded and there's no indication on the backend about the modification. This makes it harder to change fields, dependencies etc later on and it might cause problems if someone works on the site who doesn't know about that hook. So while it will solve this problem well, I'm worried it will cause others down the line. Of course, the same thing can be said about my hook above which just disables the field ?

Another thing is that I would like the fields to be visible, just not editable, like a readonly field. So removing them entirely is not an option in this case. Though I will consider this approach for similiar problems, so thanks!

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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...