Skip to content

Dynamic prefill

Paid add-on. A form can arrive already filled in: from the signed-in account, a declared URL parameter, a fixed value, or a business source plugged in through a PHP filter.

This document describes what the module guarantees and what it refuses. The user guide gives the short version, under “Arriving with the form already filled in”.

The browser never chooses a protected value

That is the decision governing everything else. Every value comes from a source the server reads itself, and the only one the visitor controls — the URL — is the most tightly framed.

The five sources

  • The signed-in account’s profile: first name, last name, display name, email address. Four properties, and not one more. Opening the list to any property of WP_User would allow a hashed password or an activation key to be prefilled — fields that exist on the object and that you do not picture while writing the rule.
  • The signed-in account’s metadata, under the same refusals as writing: no wp_ prefix, no capabilities key, no session token.
  • A URL parameter, under a name declared in the setting.
  • A fixed value, written in the setting.
  • A PHP filter, for a source specific to the site.

No source goes and fetches data elsewhere at render time. An outbound request triggered by displaying a public form would be an open door: the address would come from a setting, the answer would enter the page, and the render time would depend on a third party.

The account read is the session’s

The resolver has no user parameter: it calls get_current_user_id() itself. Accepting one from a setting or a URL would have been enough to display somebody else’s profile in a public form — and the temptation to add “just for administrators” would have come next.

A visitor who is not signed in gets nothing from the account sources. That is not an error, it is the absence of data: the field stays empty and the form stays usable.

The URL key is named, and distinct from the field

A parameter called firstname does not fill the firstname field: a rule must explicitly declare “the firstname field is filled from the code parameter”. Without that naming, every field would become fillable through a forged address.

The value is capped at two hundred characters and goes through the field type’s sanitisation. A URL parameter is shared, bookmarked, indexed and appears in logs: nothing confidential should travel through one.

What no rule can target

Password, payment, file, signature — and everything the core declares sensitive.

  • Prefilling a secret would make it appear in a page, and therefore in a cache, a history, a screenshot.
  • A payment amount is decided by the server at the moment of paying; imposing it from a URL would amount to letting people choose what they pay.
  • No prefilled value corresponds to a file or a signature: an injected path would designate a file on the server, and a prefilled stroke would be a signature nobody drew.

Locking

A locked field is displayed read-only — readonly, not disabled: a disabled field is not sent at all, and the server would receive an empty value where it expects the one it decided on.

The visible lock is not the guarantee. What a browser displays can be changed. The guarantee is that the server rewrites a locked field’s value at submission time, before validation — the re-imposed value therefore follows exactly the same path as typed input, and bypasses no check.

Rewriting rather than refusing: refusing would punish somebody whose page had simply been open for a long time, where rewriting gives the expected result.

If the value can no longer be resolved — the visitor signed out, the parameter disappeared — the field keeps what it carried rather than being emptied: emptying it would fail the validation of a required field without anyone having done anything wrong.

The lock is offered only on free-input fields. readonly has no effect on a dropdown or a checkbox, and offering a lock that locks nothing would be worse than not offering it.

The PHP filter

add_filter(
	'solis_forms_pro_prefill_value',
	static function ( string $value, string $key, string $field ): string {
		return 'case_number' === $key ? my_case_number() : $value;
	},
	10,
	3
);

The filter receives the declared key, the target field and the form. What it returns then goes through the field’s sanitisation, like everything else. It is the one place provided for plugging in a source specific to the site: it lives in code, under the responsibility of whoever writes it.

Repeatable rows

The server fills in what exists at render time. A row added afterwards did not exist, and the repeater empties it as it clones: the front-end module then copies into it what the server had put in the first one.

It reads that value on load, before any keystroke. Reading it later would copy the visitor’s input into the following rows, which nobody asked for. It reads neither URL, nor account, nor setting: a value the browser chose would not be a prefill but disguised input.

What the module does not do

No arbitrary REST request, no CRM connector, no write-back to the profile, no reading of somebody else’s submission, no secret carried in a URL.