Building Custom Input Fields in ProcessWire: Bridging Fieldtype and Inputfield
Learn how to extend the ProcessWire admin interface by creating custom Fieldtype and Inputfield classes to handle specialized data storage and UI rendering.
28 Mar 2026, 02:30 UTC

The Problem: Standard Fields Aren't Enough
ProcessWire provides a robust set of default field types, but complex data requirements—such as a specialized coordinate picker, a custom API-driven dropdown, or a formatted financial input—often require a custom UI. The challenge is that ProcessWire decouples how data is stored (the Fieldtype) from how it is interacted with in the admin panel (the Inputfield).
Prerequisites
- A running installation of ProcessWire (v3.x recommended).
- Basic knowledge of PHP and Object-Oriented Programming (OOP).
- Administrator access to the
/site/modules/directory.
Step 1: Define the Fieldtype (Storage Layer)
The Fieldtype class manages the database schema and how the value is sanitized before being saved. Create a file in /site/modules/FieldtypeMyCustomField.module.
class FieldtypeMyCustomField extends Fieldtype {
public function __construct() {
// Define the database column type
$this->dbType = 'varchar';
$this->dbSize = 255;
}
public function saveToDatabase($value) {
// Ensure the value is a string before saving to prevent SQL errors
return (string) $value;
}
}
Step 2: Define the Inputfield (UI Layer)
The Inputfield class handles the HTML rendering in the admin interface. This class must match the naming convention of the Fieldtype to be automatically linked. Create /site/modules/InputfieldMyCustomField.module.
class InputfieldMyCustomField extends Inputfield {
public function render() {
// The value is accessed via $this->value
$html = '';
$html .= 'name . '\\" value=\\"' . $this->value . '\\" class=\\"inputtext\\" \/>';
$html .= 'Custom helper text for this field.
';
$html .= '';
return $html;
}
public function validate() {
// Example: Prevent empty submissions
if (empty($this->value)) {
$this->error = 'This field cannot be left blank.';
return false;
}
return true;
}
}
Step 3: Registration and Implementation
- Upload both files to
/site/modules/. - Log into the ProcessWire Admin.
- Navigate to Setup > Fields > Add New.
- Select your custom field type from the Type dropdown.
- Assign the new field to a Page Template.
Comparison: Fieldtype vs. Inputfield
| Responsibility | Fieldtype | Inputfield |
|---|---|---|
| Database | Defines column type and size | No database interaction |
| Admin UI | No UI logic | Renders HTML/JS |
| Validation | Type safety (e.g., casting to int) | User-facing error messages |
| Lifecycle | saveToDatabase() | render() |
Verification and Diagnostics
To verify the implementation is working correctly, perform these three checks:
- UI Check: Create a page using the template. Confirm the custom HTML renders without breaking the admin layout.
- Persistence Check: Enter a value, save the page, and refresh. If the value disappears, check the
saveToDatabase()method in the Fieldtype class. - Validation Check: Trigger your
validate()logic (e.g., leave the field empty) and confirm the admin displays the error message.
Diagnostic Tip: If the field does not appear in the \"Add New Field\" dropdown, check the PHP error logs. A syntax error in the module file will prevent ProcessWire from registering the class.
Limitations and Risks
- Cache Inconsistency: Never use raw SQL queries to update custom field data. Always use the ProcessWire API (e.g.,
$page->set('field_name', 'value')) to ensure the internal cache is cleared. - XSS Risks: When using
render(), always sanitize$this->valueif it is being output directly into HTML to prevent Cross-Site Scripting.
Rollback Procedure
- Delete the
FieldtypeMyCustomField.moduleandInputfieldMyCustomField.modulefiles from/site/modules/. - Go to Setup > Fields and delete the field instance from the system.
- Remove the field from any associated Page Templates.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.