Selectors
Selectors parses a ProcessWire selector string (or selector array) into an iterable collection of Selector objects, and can test whether a given Wire-derived item matches those conditions
It is the engine behind selector
matching used throughout the core ($pages->find(), WireArray::find(),
$page->matches(), etc.).
Two classes live in this directory:
Selectors(Selectors.php) — extendsWireArray; holds a set ofSelectorobjects, parses strings/arrays into them, and matches items.Selector(Selector.php) — the abstract base for a single condition (field + operator + value), with one concrete subclass per operator (SelectorEqual,SelectorContains,SelectorGreaterThan, etc.). The operator is fixed by the subclass and cannot be changed on an existing instance.
Most code never constructs these directly — you pass selector strings to API
methods like $pages->find('template=basic-page, limit=10'). Use this class
directly when you need to parse, inspect, or match selectors yourself (for
example in a module that filters arbitrary Wire objects).
$selectors = new Selectors();
$selectors->init("sale_price|retail_price>100, currency=USD|EUR");
if($selectors->matches($page)) {
// $page matches the selector
}The constructor also accepts the selector directly, though a separate init()
call is the documented preference:
$selectors = new Selectors("template=basic-page, limit=5");Pass a selector string to the constructor or init(). The string is split into
individual Selector objects (one per comma-separated condition), each
exposing its field(s), operator, and value(s).
$selectors = new Selectors("template=basic-page, title%=about, sort=-modified, limit=5");
foreach($selectors as $selector) {
echo $selector->field(); // e.g. "template"
echo $selector->operator(); // e.g. "="
echo $selector->value(); // e.g. "basic-page"
}OR conditions with the pipe
A pipe | in a field or value indicates an OR condition. The corresponding
field()/value() accessors return a string for a single item, or an array
when multiple are present. Use the always-array forms fields() and values()
when you don't want to special-case that.
$selectors = new Selectors("title|body|summary%=foo|bar");
$s = $selectors->first();
print_r($s->fields()); // ['title', 'body', 'summary']
print_r($s->values()); // ['foo', 'bar']Casting back to a string
$selectors = new Selectors("template=basic-page, limit=5");
echo (string) $selectors; // "template=basic-page, limit=5"init() (and the constructor) also accept an array. This is useful when values
come from variables, because each value is sanitized automatically. Several
formats are supported and may be mixed in one array.
// Associative: field => value (operator defaults to "=")
$selectors = new Selectors([
'template' => 'basic-page',
'title' => 'About Us',
]);
// Operator appended to the key
$selectors = new Selectors([
'title%=' => 'about', // title %= about
'created>' => '2024-01-01',
]);
// Indexed verbose entries
$selectors = new Selectors([
[ 'field' => 'title', 'operator' => '%=', 'value' => 'about' ],
[ 'field' => 'price', 'operator' => '>', 'value' => 100 ],
]);
// Self-contained "key=value" strings (also mixable with the above)
$selectors = new Selectors([
"template=article",
"sort=-date",
"limit" => 3,
]);OR groups in selector arrays
An indexed associative sub-array represents one OR group. At least one selector inside the group must match:
$selectors = new Selectors([
[
'title%=' => 'processwire',
'summary%=' => 'processwire',
],
'template' => 'article',
]);Multiple indexed associative sub-arrays are multiple OR groups, and each group must have at least one matching selector.
Verbose array options
A verbose entry is an associative array that supports these keys:
field(orfields) — field name or array of names. Required.value(orvalues) — value or array of values. Required unlessfindused.operator— defaults to=.not— boolean; makes it a NOT condition.sanitize(orsanitizer) — sanitizer method applied to each value (defaultselectorValue).whitelist— array of allowed values; a value not in the list throws aWireException.group(oror) — OR-group name.find— a sub-selector array used instead ofvalue.
$selectors = new Selectors([
[
'field' => 'status',
'operator' => '=',
'value' => $userInput,
'whitelist' => ['active', 'pending', 'closed'],
],
]);Field names in array form are validated with $sanitizer->fieldName(); an
invalid field name throws a WireException. Array input is the safest way to
build selectors from user-supplied data.
matches(Wire $item) returns true if the item satisfies every condition
(conditions are ANDed; pipes within a condition are ORed).
$selectors = new Selectors("color=blue, qty>3");
$item = new WireData();
$item->color = 'blue';
$item->qty = 5;
$selectors->matches($item); // trueIf the item implements WireMatchable (as Page does), matching is delegated
to that object's own matches() method. For other WireData objects, dot
syntax field names (e.g. parent.title) are resolved via getDot().
You can also match a single condition directly with a Selector:
$s = new SelectorEqual('title', 'About Us');
if($s->matches($page)) {
// $page->title === 'About Us'
}getSelectorByField($fieldName, $or = false, $all = false)
Returns the first Selector whose field matches the given name, or null.
Handy for reading reserved properties such as limit, start, or include.
$selectors = new Selectors("template=basic-page, limit=5");
$limit = $selectors->getSelectorByField('limit');
echo $limit ? $limit->value() : 'no limit'; // "5"$or— also consider fields that appear inside an OR expression (a|b|c).$all— return an array of all matching selectors instead of just the first (the return type becomes an array, empty if none).
getSelectorByFieldValue($fieldName, $value, $or = false, $all = false)
Like the above, but also requires the value to match. 3.0.142+
getAllFields($subfields = true)
Returns an array (keyed by field name) of every field referenced across all selectors.
Pass false to collapse field.subfield to just field.
$selectors = new Selectors("title%=foo, parent.name=bar");
print_r($selectors->getAllFields()); // ['title' => 'title', 'parent.name' => 'parent.name']
print_r($selectors->getAllFields(false)); // ['title' => 'title', 'parent' => 'parent']getAllValues()
Returns an array (keyed by value) of every value referenced across all selectors.
$selectors = new Selectors("template=basic-page, status=1|2");
print_r($selectors->getAllValues()); // ['basic-page' => 'basic-page', '1' => '1', '2' => '2']These analyze selector/operator strings without needing a Selectors
instance. All are static.
Selectors::stringHasOperator($str, $getOperator = false)
True if the string appears to contain a selector operator preceded by a valid
field name. Pass true for $getOperator to return the operator string
instead of a boolean. Math-like strings (e.g. 1+1) are not treated as
selectors.
Selectors::stringHasOperator("title=foo"); // true
Selectors::stringHasOperator("1+1"); // false
Selectors::stringHasOperator("title%=foo", true); // "%="Selectors::stringHasSelector($str)
Stricter check that the whole string parses as one or more valid selectors.
Selectors::isOperator($operator, $returnOperator = false)
True if the given string is a recognized operator. With $returnOperator,
returns the corrected operator string (fixing minor mix-ups like reversed
order) or false.
Selectors::isOperator('%='); // true
Selectors::isOperator('xyz'); // falseSelectors::getOperatorType($operator, $is = false)
Returns a short type name for the operator (e.g. '=' → "Equal",
'*=' → "Contains"), or false if unrecognized. Pass true for $is to get
a boolean.
Selectors::getOperators(array $options = [])
Returns information about all available operators. Options control indexing and value type:
operator— restrict to a single operator (return value is then a single value, not an array).compareType— filter to operators matching aSelector::compareType*constant.getIndexType—'operator','className','class', or'none'(default'class').getValueType—'operator','class','className','label','description','compareType', or'verbose'(default'operator').
// All operators as a simple list
$ops = Selectors::getOperators(['getIndexType' => 'none']);
// Verbose info keyed by operator
$info = Selectors::getOperators([
'getIndexType' => 'operator',
'getValueType' => 'verbose',
]);Selectors::getOperatorChars() / Selectors::getReservedChars()
Return the set of characters used by operators, and the special characters with
meaning in selectors (|, !, ,, @, quotes, group/sub-selector
delimiters).
Selectors::newSelector($field, $operator, $value) 3.0.260+
Construct the correct Selector subclass for an operator. Throws if the
operator is unrecognized.
$s = Selectors::newSelector('title', '%=', 'about');Selectors::getSelectorByOperator($operator, $property = 'instance') 3.0.160+
Returns a blank Selector instance for the operator (populate its field and
value afterward), or a single requested property: 'label', 'compareType',
'class', or 'className'.
A Selector exposes its parts as methods and as magic properties.
$s = $selectors->first();
$s->field(); // string: one field, or multiple fields joined with "|"
$s->field(false); // string if one field, array if multiple
$s->fields(); // always an array of field names
$s->operator(); // operator string, e.g. "%="
$s->value(); // string: one value, or multiple values joined with "|"
$s->value(false); // string if one value, array if multiple
$s->values(); // always an array of values
// Magic properties
$s->field; $s->fields; $s->value; $s->values;
$s->operator; // read-only; fixed by the subclass
$s->not; // bool, is this a NOT condition
$s->group; // OR-group name or null
$s->quote; // quote char the value was wrapped in, or ''
$s->str; // string form of this selector, e.g. "title%=about"Per-subclass metadata is available statically: getOperator(), getLabel(),
getDescription(), and getCompareType().
- Source files:
wire/core/Selectors/Selectors.phpandwire/core/Selectors/Selector.php. - Selector language docs: for broader page-finding selector syntax and examples, see https://processwire.com/docs/selectors/.
- Operator reference: for detailed selector operator behavior, see https://processwire.com/docs/selectors/operators/.
SelectorsextendsWireArray, so allWireArraymethods (iteration,first(),count(),each(), etc.) are available on a parsed selector set.- Conditions are ANDed; pipes are ORed. Multiple comma-separated selectors must all match; pipe-separated fields or values within one selector match if any one does.
- Operator is immutable on a
Selector— it is determined by the concrete subclass. To change an operator, create a newSelector(e.g. withSelectors::newSelector()). - Prefer array input for user data. When building selectors from untrusted
input, use the array form so values are sanitized (default
selectorValue) and can be constrained with awhitelist. If building strings manually, sanitize values yourself with$sanitizer->selectorValue(). - API variable references in
[...]-quoted values are resolved at parse time:template=[page.template]expands to the current page's template name. Variables available by default:page,user,session, plus any registered viasetCustomVariableValue(). field()/value()vsfields()/values():the singular method forms always return a string by default — multiple items are joined with"|". Passfalseto get string-or-array instead (same as the magic property$s->field). The pluralfields()/values()always return arrays regardless.- Values containing commas must be quoted or supplied via the array form, since
commas are the condition separator in selector strings:
title="hello, world"or['title' => 'hello, world'].
Click any linked item for full usage details and examples. Hookable methods are indicated with the icon. In addition to those shown below, the SelectorGreaterThan class also inherits all the methods and properties of: Selector, WireData and Wire.
Common
Additional methods and properties
In addition to the methods and properties above, SelectorGreaterThan also inherits the methods and properties of these classes:
API reference based on ProcessWire core version 3.0.266