Generates .phpstorm.meta.php/ directory for ProcessWire API autocompletion in PhpStorm.
The directory approach is more robust than a single-file .phpstorm.meta.php and avoids
known issues
with the single-file format.
- Autocomplete wire container keys for
wire('...')andWire::wire('...') - Autocomplete module names for
Modules::get()andModules::install() - Autocomplete field names for
Fields::get() - Autocomplete template names for
Templates::get() - Autocomplete unique page names for
Pages::get() - Autocomplete hookable methods for
Wire::addHook*() - Autocomplete page status constants/strings for
Page::status(),addStatus(),removeStatus(),hasStatus() - Autocomplete field flags for
Field::addFlag(),removeFlag(),hasFlag() - Autocomplete template cache-expire constants for
Template::cacheExpire() - Autocomplete Inputfield collapsed constants for
Inputfield::collapsed() - Autocomplete sort flags for
WireArray::sort()/sortFlags()/unique()andPageArray::sort()/sortFlags()/unique() - Optional: Field type autocompletion per Page class (when enabled in module config)
- Incremental writes: Only changed files are written — no git noise from unchanged files
- Deterministic ordering: All dynamic sections use stable alphabetical sorting
- Copy the module folder into
site/modules/ProcessWirePhpStormMeta/. - Install the module in the ProcessWire admin.
- Default path:
site/assets/.phpstorm.meta.php/(configurable in module settings). - The directory is regenerated automatically when fields, templates, or modules change (debounced).
- You can manually regenerate from the module settings screen.
- Optional: enable "Generate page-class field metadata" in module settings for field type hints per Page class. This is intentionally basic. For richer field stubs, use AutoTemplateStubs.
admin(default): module runs meta generation only on admin requests.always: runs on every request — useful when frontend hooks trigger regeneration.
All settings can be set in site/config.php. Values set here are shown as disabled in the module UI:
$config->ProcessWirePhpStormMeta = [
'autoloadMode' => 'always',
'autoRegenerate' => true,
'generatePageClassFieldMeta' => true,
];Add custom completions via the generateCustomMetaContent() hook. Multiple hooks concatenate.
The output lands in custom.meta.php inside the meta directory.
This example autocompletes block names for renderBlock() — a custom function that
renders site/templates/blocks/*.php partials:
// $content = renderBlock('hero', $page);
$wire->addHookAfter("ProcessWirePhpStormMeta::generateCustomMetaContent", function($event) {
$names = [];
foreach (glob(wire()->config->paths->templates . "blocks/*.php") ?: [] as $f) {
$names[] = pathinfo($f, PATHINFO_FILENAME);
}
if (empty($names)) return;
$custom = "\n registerArgumentsSet(\"block_names\",\n";
foreach ($names as $n) $custom .= " \"{$n}\",\n";
$custom .= " );\n\n";
$custom .= " expectedArguments(\\ProcessWire\\renderBlock(), 0, argumentsSet(\"block_names\"));\n";
$event->return .= $custom;
});$tracy = $modules->get('TracyDebugger');
// Autocomplete + correct class type for navigation and code insight$page = wire('page');
$pages = $this->wire('pages');
$cache = wire('cache');
// Autocomplete for keys like page/pages/cache/etc.$body = $fields->get('body');
// Autocomplete field names, fewer typos$tpl = $templates->get('basic-page');
// Autocomplete template names$home = $pages->get('/');
// Maps to the page class when page classes are enabled$page->status(Page::statusHidden);
$page->addStatus('draft');
$page->removeStatus(Page::statusUnpublished);
$page->hasStatus('locked');$field->addFlag(Field::flagAutojoin);
$field->removeFlag(Field::flagAccess);
$field->hasFlag(Field::flagGlobal);$template->cacheExpire(Template::cacheExpireParents);$inputfield->collapsed(Inputfield::collapsedYesAjax);$items->sort('title', SORT_NATURAL | SORT_FLAG_CASE);
$items->sortFlags(SORT_NATURAL);
$items->unique(SORT_STRING);$home = $pages->get('/');
// $home is HomePage (page class)
// Field types are inferred from the template fieldgroup
// e.g. $home->hero_image -> Pageimage or Pageimages depending on field settings$wire->addHookAfter('Pages::save', function($event) {
// Autocomplete hookable methods while typing the hook string
});- Hook scanning reads ProcessWire core, modules, admin templates, and page classes to build the hook list.
- If page classes are enabled, page names map to their page class; otherwise they map to
Page. - All dynamic entries are alphabetically sorted to ensure stable, deterministic output.
- Improvement suggestions and PRs are welcome.
Mozilla Public License 2.0. See LICENSE.