Search the Community
Showing results for 'template'.
-
Hey everyone! Our frontend developer saw GitSync and said "this is lovely for module repos — but what I actually want is the whole /site/ on a branch. Push, switch, done." Reasonable. We said "yeah, we'll get to that." That was a while ago. SiteSync is what we eventually built. What it does: SiteSync deploys a ProcessWire installation's /site/ from a configured GitHub repository — one repo active at a time, but repoint it whenever you like, we're not the boss of you. Every template, stylesheet, RockMigrations config file, content seed lives on a branch. The admin lists every branch in the repo, you click Switch, /site/ is atomically replaced with that branch's tree, RockMigrations applies schema changes on the refresh hook, content seeds run. Click another branch, switch back. Click Rollback on yesterday's deploy, you're on yesterday's deploy. No git binary on the server, no CI runner, no SSH keys — everything goes over the GitHub REST API from PHP. What's new here: Coding-agent fluent. An AI coding agent (Claude Code, Cursor, OpenAI Codex, …) reads a shipped AGENTS.mdfrom your ProcessWire root — which SiteSync auto-scaffolds on install — edits files on a feature branch, opens a draft PR, and the SiteSync admin shows you updates available. We bootstrapped a complete blog — schema, templates, styling, three seed articles — from an iPhone with the Claude app. No laptop in the loop. Real staging via two installs. One SiteSync per environment, both pointed at the same repo, different active branches. Feature → PR onto staging → staging auto-deploys → browse staging.example.com like an actual human → second PR onto live-stable → live deploys. Schema changes hit the staging DB first, not directly into live. The grown-up workflow you usually pay a SaaS for. The technical guts: Versioned everything. Each deploy is <branch> + <SHA> + <commit title> in the Recent deploys table. One-click Rollback to any prior row — the rollback is itself just a regular deploy of that exact tree, same atomic two-pass write, same snapshot, same tracked-sync. Tracked sync, not strict mirror. A new file in your branch shows up on the server. A file your branch never knew about (a third-party module's helper, a hand-edited template, last night's debug log) stays where it is. SiteSync only deletes what SiteSync itself wrote — verified by per-file blob SHA in managed-files.json. Atomic two-pass write. Pass 1 downloads every blob to <final>.sitesync-tmp next to its target. Any failure cleans up all tmp files; /site/ is never half-mutated. Pass 2 POSIX-renames each tmp → final. Pre-deploy snapshots as tar.gz, configurable retention, one-click restore. Your /site/ before SiteSync touches it. If you've ever pasted find . -delete into the wrong shell, this is your safety net. Webhook with hold-back. A direct edit on the server (3am emergency typo fix) is detected; the next webhook push to that same path is held back with HTTP 409 + a clear admin banner instead of silently overwriting your hotfix. The push waits patiently for you to commit and push the local change. Fits your stack: RockMigrations marriage. Fields, templates, roles, permissions as config files under site/RockMigrations/. SiteSync deploys the files and calls $modules->refresh() — RockMigrations hooks the refresh and applies your schema changes. No custom post-deploy step, no extra wiring. Schema-as-code that actually deploys. Editorial seeds under site/content/ for the "first article" / "bootstrap pages" problem — every .php file in there runs on every deploy. The bundled AGENTS.md documents the conventions for keeping seeds safe: idempotency guards (so a re-deploy doesn't duplicate content), and versioned filenames like 99-patch-rename-foo-v1.php for the rare "we need to rename this on every install" case. Conventions, not magic — your seeds are plain PHP doing whatever you want. What it doesn't try to do: replace your CI, sync site/assets/ (uploads stay where the editor uploaded them), or pretend to be a fleet deployer. One site, one active repo, one Switch at a time. The simplicity is the point. Beta status: in active use on real ProcessWire sites. The atomic-deploy + tracked-sync + hold-back + snapshot machinery is stable. The agent-templates and staging walkthrough landed in the most recent sprint and would benefit from more real-world miles. Bugs, edge cases, and "wait, that's a weird hosting setup" reports very welcome. Boring details: License: MIT. Requires: ProcessWire 3.0+, PHP 8.0+ with curl and phar extensions. GitHub token: fine-grained PAT, Contents: read only — read-only. SiteSync literally cannot modify your repo. If the server is ever compromised, the token can pull source code but not push anything back. Get it: Repository: https://github.com/frameless-at/SiteSync Install: drop into /site/modules/SiteSync/, Modules → Refresh → Install README has the whole tour: config, webhooks, path filters, staging walkthrough, agent workflow. Companion to (but not dependent on) GitSync — install both side by side if you want module-level granularity and whole-/site/ branch deploys. SiteSync can even reuse GitSync's GitHub token, because typing the same PAT twice is a crime. One last flex: For a proof of concept we just used SiteSync in combination with Claude to migrate a 20-year-old blog — articles, comments, gallery images, the lot — out of its previous CMS into a fresh ProcessWire install. We just installed the module, pushed /site/ to a Repo and connected the agent to it. We fed it with a JSON Dump of the Blog-Data and said what we wanted: Schema as files on a branch, content as idempotent seeds, snapshots between attempts because of course the image migration didn't work on the first run (or the second, or the third). New /site/ deployed clean, two decades of writing intact, old URLs preserved. Tataaaa. Curious to hear how it lands in your setup. Cheer, Mike
-
- 3
-
-
-
Hi, A small but practical module for anyone working with ProFields Repeater Matrix on the frontend. GitHub: https://github.com/mxmsmnv/InputfieldMatrixType The problem Repeater Matrix is great for building flexible content blocks — but when you need to identify item types programmatically, things get messy fast. Types are stored in internal template names like repeater_matrix_123, there's no clean way to get a human-readable type identifier, and extracting structured data from different item types means repetitive code in every template. I ran into this building a gift catalog on e-commerce project — a matrix field with three item types: Box, Handbag, and Bouquet. Each has different fields and pricing. I needed clean type identifiers for frontend rendering and a JSON API for Alpine.js components. What it does FieldtypeMatrixType — a dedicated field for storing type identifiers per matrix item (e.g. box, handbag, bouquet) InputfieldMatrixType — admin UI to configure identifier and display name per type MatrixDataProcessor — PHP class that extracts all matrix item data into a consistent structured array, JSON-ready $processor = new MatrixDataProcessor($page); $items = $processor->getItems('opt'); echo json_encode($items); Each item returns id, type, displayName, price, and a fields array with name/label/type/value — ready for Alpine.js, Vue, or any API endpoint. Supports Text, Textarea, Options, Checkbox, Integer, Float, Page references, and Image fields out of the box. Custom field types via formatValue() override. Requirements: ProcessWire 3.0+, PHP 8.1+, ProFields Repeater Matrix MIT License.
- 1 reply
-
- 9
-
-
Dear @Nomak, your project sounds straightforward and well-prepared. Since you already have a fully completed design and will handle the backend yourself, I can focus entirely on delivering clean, responsive, and high-performance frontend code. Here is why I am a great fit for this project: Location & Legal: I am based in the EU (Germany) and will provide a valid EU VAT ID for proper, hassle-free invoicing. Experience & Modern Tech Stack: I have been working in web development since 1995, meaning I understand the core of the web inside out. However, I always stay on the cutting edge. For modern, responsive, and maintainable styles, I highly leverage Tailwind CSS, alongside clean HTML and robust JavaScript. Efficiency through AI: I actively integrate modern AI tools into my workflow, which allows me to speed up the development process, optimize code efficiency, and deliver high-quality results faster. Responsive Execution: Ensuring a seamless experience across desktop, tablet, and mobile devices is standard practice in my work. You can convince yourself of the quality of my work by taking a look at my portfolio: 👉 dotnetic.de/referenzen I would love to realize this project with you. Let’s connect to discuss the details and the design template. Best regards, Jens
-
I have quite a quite large template having 57 fields. Now the saving of a page with that template takes over a minute on the production server. The server is a shared webhotel server with PHP 8.2. On my own vps server the saving takes under 3 seconds. Tracy shows in the timers for the last save stage, the redirect to ?id=222&s=1&c=0, 1,2 seconds time. But the Execution time for this in System info is 1400 ms. Where can I see what causes the one minute delay? I can't find the point in Tracy panels to debug more.
-
Hello, I need some advice on what is the best option to set permissions for Repeater Matrix. I am using a Repeater Matrix with multiple Repeater Matrix types in a template. The main Repeater_matrix_field consists of around 10 items with image, text fields and various layouts. What I am trying to do is to limit permissions and prevent a user role from editing. How can I restrict access to certain Repeater Matrix types so that all fields are locked except 2 Repeater Matrix types? Is that possible? Repeater_matrix_field structure: 1. Repeater Matrix item: Full size image field 2. Repeater Matrix Item Two Column text fields 3. and 4. Repeater Matrix Item. The only field that the user should be allowed to edit 5. Repeater Matrix Item: Text Teaser fields 6. Repeater Matrix Item: Full size image field 7. Repeater Matrix Item: Two Column text fields What is the most elegant way to set the permissions? Option A. I have looked into RestrictRepeaterMatrix module. However it still possible to modify and delete existing Repeater Matrix types. Option B. Usually I would add a separate field with individual permissions, but adding 2 more Repeater Matrix duplicates seems to be overkill. Also both fields are located in the middle of the Repeater Matrix field. The option to change the item order is essential. I hope this makes sense. I really appreciate any reply.
-
module StripePaymentLinks – Simple Checkout Integration for ProcessWire
Mikel replied to Mikel's topic in Modules/Plugins
StripePaymentLinks 1.2.0 — Electronic withdrawal for B2C distance contracts Hi all, just shipped new version of StripePaymentLinks, which adds a complete electronic right-of-withdrawal flow for online merchants. Why now EU Directive 2023/2673 (amending the Consumer Rights Directive 2011/83/EU) requires every online trader selling to EU consumers — goods, services, or digital products — to provide an easily accessible "withdrawal button" by 19 June 2026. Member states had to transpose the directive into national law by 19 December 2025; Austria's FAGG amendment is one of the implementations now landing. The guiding principle: withdrawing from a contract must not be more burdensome than concluding it. This module ships an electronic withdrawal flow that satisfies that principle, with all legal wording editable per site so it works under any national transposition. What's new Withdrawal modal on every frontend page — Bootstrap 5 modal with form → confirmation → success steps. Renders only when invoked (link or ?withdraw=1 URL parameter); zero overhead otherwise. Per-user withdrawal log — every submission is stored in a repeater on the user template (spl_withdrawals) with timestamp, products affected, salted HMAC-SHA256 IP hash, and a status field that the merchant can update from the backend. Two-mail flow — the customer gets a confirmation of the withdrawal, the merchant gets an internal notification with a direct link to the user profile. Both go through the existing universal mail layout. Order-confirmation mail now includes a consumer-rights block — auto-injected for every purchase, with two outcomes depending on the product: Right of withdrawal applies → withdrawal instructions are rendered. Right has been waived (e.g. immediate digital delivery with explicit consent) → waiver acknowledgement is rendered. Site-editable legal text — two TinyMCE config fields (mailWithdrawalText, mailWaiverText) let each site operator write the exact legal wording their jurisdiction requires. Placeholder system including {products}, {provider}, {contact_email}, {order_id}, {order_date}, {name}, {email}, {today} and — for the TinyMCE editor — anchor-pair placeholders that survive the editor's href-stripping: {withdrawal_mail}TEXT{withdrawal_mail_end} → expands to a prefilled mailto: link (subject + body from translatable defaults) {withdrawal_online}TEXT{withdrawal_online_end} → expands to a ?withdraw=1 deeplink that auto-opens the modal Built-in protection — honeypot field, per-IP rate-limit, server-side CSRF, deliverability headers (Auto-Submitted, X-Auto-Response-Suppress, proper Reply-To). Setup is a few field saves ... In the module config there's a new Withdrawal fieldset with five fields: Internal notification email (falls back to $config->adminEmail) Contact email shown in the form (falls back to sender email) Privacy policy page (page-select) Withdrawal text — right of withdrawal applies (TinyMCE) Waiver text — right of withdrawal does not apply (TinyMCE) The module creates all required fields, the spl_withdrawals repeater and status options on first save / module upgrade — fully idempotent. ... and adding the trigger link to your templates The withdrawal modal is auto-injected on every frontend page — you only need to render a link to open it. The module ships a helper for that: echo $modules->get('StripePaymentLinks')->renderWithdrawalLink(); That gives you the legally required, always-visible withdrawal entry point. Typical place: site footer or account menu. The helper takes two optional arguments — a CSS class and a custom label — so it adapts to whatever markup your theme uses: echo $modules->get('StripePaymentLinks')->renderWithdrawalLink('nav-link fw-bold'); echo $modules->get('StripePaymentLinks')->renderWithdrawalLink('', 'WITHDRAW'); Anything that links to your site root with ?withdraw=1 also auto-opens the modal — useful for putting a direct withdrawal link inside order-confirmation mails, transactional notifications, or PDF receipts. That's the whole frontend integration — one helper call, no JavaScript wiring, no modal HTML in your templates. Translatable All UI strings (modal labels, mail subjects/bodies, status names) are PW-translatable. Happy to hear feedback, edge cases, or implementation experiences from other EU jurisdictions. Cheers, Mike -
@adrian the full knowledge means templates, fields, page content, ability to read template files, know what modules are installed, etc. Most of it is provided by existing AgentTools commands (sitemaps, docs, etc)
-
PW 3.0.261 – Core updates + AgentTools updates
adrian replied to ryan's topic in News & Announcements
This sounds very cool, but I wonder if you can allay some concerns I have. Does that mean it can read any content from any field on any template/page in the site? I am just worried about it accessing and processing private data. Or does it only have access to field/template/page structure and not actual field data? -
AgentTools updates (v12) New AgentTools Page Engineer Fieldtype: provides a page editing assistant with the ability to make page edits like writing or summarizing text, importing data from external sources, generating image descriptions, managing child pages, and more. To use it, create a new PageEngineer field, add to a template and edit a page. You get an in-page assistant where you can ask for page editing help. The PageEngineer comes with full knowledge and expertise of your entire site, built in. Also new to AgentTools this week is an upgrade to the migrations system. Now you can copy/paste migrations between dev and production sites. Just check the box next to one or more migrations and click export. Transferred migrations are encrypted with unique salt values from your /site/config.php file. So for security, it's not possible for import a migration that wasn't generated by AgentTools. Lastly, AgentTools also gained a "tattletale" feature. When enabled, if you ask the agent to do something that could compromise security or is otherwise suspicious, it triggers a special tool in AgentTools that blocks the user from making further requests for an hour. It also emails you (the admin) to let you know what specifically the agent found suspicious. Core updates (3.0.261) ProcessWire 3.0.261 is on the dev branch this week and continues with our reorganization of core classes for documentation purposes. New API.md documentation files were added for: $session, $config, $files, $database, $input, $sanitizer, and PagesRaw ($pages->raw). Because most classes are getting their own directories and API.md files, I'm thinking that the WireTests module might be merged into the core, and classes and modules will come with their own tests file (i.e. Class.tests.php and ModuleName.tests.php). It just seems to make sense that tests live alongside the class they test, so that they can be easily updated with the class. All of this core recorganization is leading towards ProcessWire 4.x. LazyCron was updated with CLI support for running jobs (with option to disable http running), and $modules was updated to now have its own CLI tools (visible when typing "php index.php"). Many more API variables will be getting their own CLI tools as well. I'm now using both Claude Sonnet 4.6 and GPT 5.5 Codex to do code reviews and write API.md documentation for the core. I find they each have their upsides so am trying to put them both to good use as much as possible. This week GPT 5.5 covered several core classes, and the entire /wire/core/Pages/ set of classes. For more details on this week's updates see the full commit log here. New versions of the following ProFields have also been released this week: FieldtypeTable, FieldtypeCombo, FieldtypeCustom and FieldtypeRepeaterMatrix. In addition to new features and fixes, these all have gone through AI code reviews and now have their own API.md files as well. More modules on the way too. I think that covers everything updated this week but it's late and I'm probably forgetting something, so I'll reply with more if it comes up. Thanks for reading and h ave a great weekend!
- 21 replies
-
- 19
-
-
-
Working with AI in PageGrid Inspired by projects like AgentTools, I began investigating how well an AI could handle PageGrid’s native PW structure (Pages, Templates, and Fields). The results were surprisingly good and with a few targeted optimizations, the workflow has become remarkably solid. With the latest updates, an AI agent is reliably able to create and design PageGrid layouts, create new block templates, or perform content updates. To teach AI how to "speak PageGrid", I created a small AGENTS.md file that acts as a central hub. I’ve then added specific "skills" in separate .md files for various tasks ensuring the AI only loads the documentation it actually needs. This approach is highly optimized to minimize token consumption, allowing even "smaller" models like GPT-4o mini or Claude Haiku to produce error-free migrations. To make this possible, I also introduced dedicated Migration Functions that allow the AI to programmatically add items or set styles. For CLI-based projects, I highly recommend the AgentTools Module to streamline the integration. Beyond CLI support, AgentTools also provides a native AI interface directly within the ProcessWire backend editor. Getting Started Install the lastest version of the FieldtypePageGrid module (try for free). Tell your AI agent to read the PageGrid agent guide first: That file gives the agent everything it needs to understand PageGrid and routes it to the right documentation for your task. What You Can Ask the AI to Do Build or modify a layout Create pages with blocks, apply styles, set up responsive layouts using CSS grid columns. Example prompts: "Create a landing page with a full-width hero section and a 3-column feature grid below it." "Add a text block and an image block side by side inside the first group on my homepage." "Make the hero block have a dark background and white text, with 60px padding on desktop and 24px on mobile." The core advantage here is that the AI doesn't write your frontend code from scratch. The HTML and logic are already defined in your PageGrid Block Templates. The AI simply acts as an orchestrator, assembling these blocks and applying styles. This ensures the output remains clean, semantic, and easy to maintain via drag-and-drop later on. Create a custom block template Define a new block type with custom fields and register it with a PageGrid field. Example prompts: "Create a custom block called pg_testimonial with a quote text field and an author name field." "Create a custom card block with a title, description, and link field, and add it to my homepage PageGrid field." Write a site template Render a PageGrid field inside your own PHP template file. Example prompts: "Show me how to render my PageGrid field inside my home.php template using markup regions." "Generate a site template for pagegrid-page that includes the PageGrid output between the header and footer." Docs Documentaion
-
Collections — Airtable-style data management for ProcessWire
iank replied to maximus's topic in Modules/Plugins
Hi @maximus, I've been trying it out this module too and really like it! I have a couple of suggestions, if that's OK? Pages that don't have template view files (<templatename>.php) still show a view icon in the collection list, resulting in a 404 when clicked. This could be solved by adding a $page->viewable() check to the $showViewLink boolean. When a template's "Can this template be used for new pages?" setting ("noParents") is set to -1 (only one page) or 1 (no new pages), the "Add [collectionItem]" button still shows. Maybe a canAddNew() method of the Collection class to hide the button in those circumstances? [this worked for me, though there may be a more elegant way, or that suits your coding style]: /** * Whether the admin "Add" button should be shown for this collection. * Mirrors ProcessPageAdd's logic on Template::noParents: * 1 → template disallows new pages * -1 → singleton; only allowed while no page using it exists yet */ public function canAddNew(): bool { $template = wire('templates')->get($this->template); if (!$template || !$template->id) return false; $noParents = (int) $template->noParents; if ($noParents === 1) return false; if ($noParents === -1) { return $template->getNumPages() === 0; } return true; } //and then in collection-list.php: <?php if ($canCreate && $collection->canAddNew()): $addTemplate = $wire->templates->get($collection->template); $addUrl = $adminUrl . 'page/add/?template_id=' . $addTemplate->id; ?> Anyway, thanks for the great module! -
I hope no-one minds, but I have removed dai() and bdai() in favour of adding a "copy as plain text for AI agent" button for the regular d() and bd() calls. which will put the following in your clipboard. Call: d($page); Location: site/assets/cache/TracyDebugger/consoleCode_1778105690621_f3xspie7xg.php:2 ProcessWire\Page #246 instanceID: 10 id: 3 name: 'page' path: '/admin/page/' status: 'locked, system' template: 'admin' parent: '/admin/' numChildren: 10 sort: 0 sortfield: 'sort' created: '2025-12-06 18:34:42 (5 months ago)' modified: '2025-12-06 18:34:42 (5 months ago)' published: '2025-12-07 12:34:42 (5 months ago)' createdUser: 'ajones' modifiedUser: 'ajones' isLoaded: 1 outputFormatting: 1 hooks: array (17) | '->render' => array (2) | | 0 => 'TracyDebugger->logRequests() in TracyDebugger.module.php' | | 1 => 'anonymous function() in TracyDebugger.module.php (100.1)' | 'Page::getRequestData' => 'TracyDebugger->getRequestData() in TracyDebugger.module.php' | 'Page::logRequests' => 'TracyDebugger->logRequests() in TracyDebugger.module.php' | 'Page::editable' => 'PagePermissions->editable() in PagePermissions.module' | 'Page::publishable' => 'PagePermissions->publishable() in PagePermissions.module' | 'Page::viewable' => 'PagePermissions->viewable() in PagePermissions.module' | 'Page::listable' => 'PagePermissions->listable() in PagePermissions.module' | 'Page::deleteable' => 'PagePermissions->deleteable() in PagePermissions.module' | 'Page::deletable' => 'PagePermissions->deleteable() in PagePermissions.module' | 'Page::trashable' => 'PagePermissions->trashable() in PagePermissions.module' | 'Page::restorable' => 'PagePermissions->restorable() in PagePermissions.module' | 'Page::addable' => 'PagePermissions->addable() in PagePermissions.module' | 'Page::moveable' => 'PagePermissions->moveable() in PagePermissions.module' | 'Page::sortable' => 'PagePermissions->sortable() in PagePermissions.module' | 'Page::cloneable' => 'PagePermissions->cloneable() in PagePermissions.module' | 'after Page::render' => 'anonymous function() in FrontendMatrixEdit.module.php' | 'before Wire::trackException' => 'anonymous function() in TracyDebugger.module.php' data: array (2) | 'title' => 'Pages' | 'process' => 'ProcessPageList' I feel like this is the best of both worlds.
-
I'm not sure exactly when, but one of the recent builds of the PW API documentation lost a reference page (that is linked from elsewhere in the documentation; which was linked from the Template's Family tab for "name format" as of v3.0.257): https://processwire.com/api/ref/pages-names/page-name-from-format/ If page URLs are adjusted based on updated documentation, might need to handle auto-redirects and check links in PW's admin as well. When there are such profound changes of pace, sometimes the pace outpaces itself. 😄 That said, nice to see some quick turnaround on things that, I'd imagine, you've wanted to tackle for some time but haven't had the desire to dig through it due to the ROI of time. That's certainly one absolutely huge benefit of AI. Looking forward to checking out the updated versions of the modules and seeing if there are any new fixes in the mix. 🙂
-
Hi everyone, I've been running this module in production a spirits catalog with 12,000+ products — for several months. Today I'm releasing it publicly. GitHub: https://github.com/mxmsmnv/Collections The problem ProcessWire's page tree is brilliant for site structure. It's painful for data management. When you have thousands of pages as records — products, listings, vacancies, menu items — you hit the same walls on every project: no table view, no inline filters, no bulk actions, no export, no REST API, no role scoping per dataset. Every PW developer has solved some version of this. Collections solves it once. Screenshots What it does Gives any ProcessWire template a configurable admin table — live search, dropdown filters, inline status toggles, bulk actions, CSV/JSON export, and a REST API — all configured through a UI, without writing code. Admin UI: Configurable columns per collection with custom labels Live search with 300ms debounce across multiple fields including Page references Dropdown filters for FieldtypePage and FieldtypeOptions fields Inline publish/unpublish toggle via AJAX Bulk actions: publish, unpublish, delete with CSRF protection CSV and JSON export with active filters preserved Role-based permissions matrix — scope each role per collection "View in Collection" button injected into the page edit form REST API: Bearer token, query param, HTTP Basic, and PW session auth API key management with expiration dates and per-key capability scopes SHA-256 hashed keys, usage tracking, rate limiting (100 req/min) WireCache support for GET responses ProFields support: Table, Textareas, Multiplier, Repeater Matrix, Combo — including dot-notation for subfields (address.city, blocks.hero.title, prices.*.amount) Field types: Text, Textarea, Integer, Float, Checkbox, URL, Email, Date, Image, File, FieldtypeFileB2, FieldtypePage, FieldtypeOptions, MapMarker, Color Requirements: ProcessWire 3.0.244+, PHP 8.2+ There's a thread from 2013 asking for exactly this: Module Idea: Flat Listings — here it is, 12 years later. Known issues are tracked on GitHub — the module is stable for production use, active development continues.
- 14 replies
-
- 22
-
-
-
PromptWire is now at v1.9 and includes a few new features and fixes. The list below is AI-generated... Diagnostics can run against production The eight read tools (pw_health, the four pw_db_* ones, pw_logs, pw_last_error, pw_clear_cache) now accept site: local | remote | both. Previously site: remote was silently ignored and queried the local database instead. Bulk page push to remote or both pw_pages_push accepts targets: local | remote | both. Pages go in parent-first order so newly-created parents exist before their children try to attach. Pull pages back from production pw_page_pull source: remote fetches a page that was edited directly in the production admin and writes it into your local sync tree, so you can re-edit and push back without touching the live admin. Phantom diffs eliminated from pw_site_compare Page content is now hashed deterministically across environments. Identical content produces identical hashes regardless of timezone, page-array storage order, or whether a date field has an output format set. pw_modules_list Lists installed modules with version, file path, and install state. Pass site: both to compare local vs production install state in one call. pw_users_list Lists users with id, name, email, roles, and any member_* fields. Pass includeAll: true for every non-system field on the user template. pw_resolve Bulk name-to-id lookup for fields, templates, pages, roles, permissions, users, or modules. Translates names into the equivalent IDs on the target site without one round trip per name. pw_inspect_template Like pw_get_template but each field comes back as {name, type, label}. Designed for spotting fieldgroup differences before pushing changes. File inventories include .module files and symlinked module directories Previously the file sync silently skipped any modules developed in symlinked sibling repos. pw_modules_list bugfix (v1.9.1) The default call with no classes filter was returning null class names. Caught during release validation and patched the same day.
-
Hi everyone, I made a small fieldtype module for storing product dimensions: https://github.com/mxmsmnv/FieldtypeDimensions FieldtypeDimensions lets you store length, width, height and optionally weight in a single field. It’s mainly useful for product/catalog/e-commerce pages where dimensions are needed for display, shipping or filtering. Supports different units (mm, cm, m, in, etc. for length and g, kg, lb, etc. for weight) and stores values internally in mm/grams. The module also supports multilingual setups — admin field labels are available in 20+ languages and can be configured globally. Basic usage example: $dim = $page->dimensions; echo $dim; // 120 × 80 × 50 mm, 1.5 kg echo $dim->lengthIn('cm'); echo $dim->weightIn('kg'); Selectors: $pages->find("template=product, dimensions.length>100"); $pages->find("template=product, dimensions.weight>500"); More details in the README. Feedback and suggestions are very welcome.
-
solved Path settings appear in the wrong fieldset tab
monollonom replied to olafgleba's topic in API & Templates
When setting $config->advanced = true you can specify in a specific template whether you want the name field to appear in the content tab. Is it maybe your case? -
Hi, We use the mod_cspnonce + Apache SSI approach. .htaccess: Options +Includes AddType text/html .html .php AddOutputFilter INCLUDES .html .php <IfModule mod_headers.c> # If not the PW admin <If "! %{QUERY_STRING} =~ /{your-admin-url}/"> ... Header set Content-Security-Policy "\ default-src 'self';\ script-src 'nonce-%{CSP_NONCE}e' 'strict-dynamic';\ ... " </If> </IfModule> In your template: <!--NoMinify--> <script src="./your-script.js" nonce="<!--#echo var="CSP_NONCE"-->"> <!--/NoMinify--> Note that the NoMinify tags need to be added to stop ProCache stripping out the SSI var as it treats it as an HTML comment. We've been using this in production for 2-3 years on sites with the Apache module available and it works well. Cheers, Chris
-
Hi everyone, in particular @ryan @Peter Knight@ukyo @gebeer @maximus who seem to have been most AI active lately. I've just added dai() and bdai() dumping calls so that objects and arrays are rendered in plain text format more friendly to LLMs, but I am curious what AI/LLM integration features you think would be most useful? Claude suggested an MCP server - here is its plan. Does this sound useful? Any other ideas? Two processes, loosely coupled: ┌──────────────────┐ ┌──────────────────────────┐ │ Claude / Cursor │ stdio MCP │ TracyDebugger site │ │ client │ ─────────────────► │ │ │ │ HTTP + token │ tracy-ai/* endpoints │ └──────────────────┘ ◄───────────────── └──────────────────────────┘ MCP server — a tiny program the agent launches over stdio (the MCP transport). Ships as a sibling module (TracyDebuggerMCP/) or a standalone npm package the user npx's. TracyDebugger HTTP endpoints — new authenticated tracy-ai/* routes inside the ProcessWire site. The MCP server is just a thin translator between MCP tool calls and these HTTP requests. The MCP server holds no site logic. It's a dumb adapter. All the real work (reading panels, redacting secrets, rendering plaintext) stays inside TracyDebugger where the ProcessWire API is available. What the agent sees A handful of tools in the MCP catalog: tracy_export_bundle(preset: "debug" | "performance" | "template" | "full") tracy_get_request_info() tracy_get_last_errors(limit: int = 10) tracy_get_slow_queries(limit: int = 10) tracy_get_template_schema(template: string) tracy_list_dumps() tracy_run_console(code: string) ← gated, opt-in only Every tool returns the scrubbed plaintext/JSON produced by AIExport — same output Phase 2's "Copy" button produces. Config on the site New module-config section: aiExportHTTPEndpointEnabled (default off) aiExportMCPToken — a random token generated once per site, shown to the user to paste into their MCP client config aiExportAllowConsoleExec (default off) — gates tracy_run_console aiExportAllowedIPs — optional whitelist Config on the client User's ~/.config/claude/mcp.json or equivalent: json { "mcpServers": { "tracy": { "command": "npx", "args": ["-y", "tracy-mcp"], "env": { "TRACY_URL": "https://mysite.test", "TRACY_TOKEN": "<paste token from module config>" } } } } The agent launches the MCP server locally; the MCP server talks to the site over HTTPS with the token. Auth Per-site token (generated in module config, rotateable). Token sent as Authorization: Bearer … header on every HTTP call. Optional IP whitelist on the site side. tracy_run_console additionally requires aiExportAllowConsoleExec=true — otherwise the MCP server gets a 403 and reports "console execution disabled for this site" to the agent. Example flow — agent debugging an error User in Claude: "Why is /about/team throwing a 500?" Agent: Calls tracy_export_bundle(preset: "debug"). MCP server hits GET https://mysite.test/tracy-ai/export?bundle=debug with the bearer token. Site responds with scrubbed JSON: request info, PW info, last error with stack, slow queries, recent PW logs. Agent reads the traceback, sees TemplateFile.php:123 Undefined index "featured_image", asks tracy_get_template_schema(template: "team"). Site responds with the template's fields — no featured_image field exists. Agent suggests the fix, possibly calls tracy_run_console (if enabled) to verify. No human pasting. Agent pulls what it needs on demand, scoped by the tool it calls. What ships where In TracyDebugger itself: the tracy-ai/* HTTP endpoints + auth + token config + AIExport (already built in Phase 1, extended in Phase 2). In the MCP server (separate repo, ~200 lines): tool definitions, HTTP calls, response shaping for MCP. This separation matters because the MCP server can be installed independently of the site, and the site is still useful without it (you can hit tracy-ai/export with curl directly). Footprint on production Zero unless you explicitly enable it. The endpoints, token, and MCP config are all opt-in behind module settings. That's the shape. The main design choices worth confirming before building: Token-only auth, or also require the existing Tracy access? — i.e., should the agent's token have to belong to an allowed Tracy dev user, or is a separate machine token fine? I'd lean separate machine token for agents; reusing session auth is awkward over stdio. Read-only by default? — I strongly recommend yes. tracy_run_console is the only write path and should be a separate opt-in. Does the MCP server live in this repo or a separate repo? — I'd say separate. Different language, different release cadence, and the site works without it.
-
I know a reasonable amount about the output formatting basics. But I keep finding it behaving unreliably so I'm looking to enhance my understanding, or find fixes. Example: A template ('basic page') contains a Page Table Next (ptn) field. One of the templates in use in the ptn field has a repeater field. I'm rendering with Latte and I wish vars holding Page[Array] objects exposed to my templates to have of(TRUE) Let's say $thePage holds the basic page in question. There's 2 overarching contexts, front and back end. On admin screens pages default to of(FALSE) on front end, of(TRUE) This is already a bit of a problem that need workaround, since Page Table Next renders the front end output in the back end. But the question is, after $thePage->of($bool) what is the output formatting state of: $thePage->ptn->first ? $thePage->ptn->first->repeaterField->... ? It's not reliably $bool. I've sometimes tried to bolster the reliability by also calling $wire->pages->of($bool). But I still find it's not always as expected. In the case of linked pages, as above, how does an instantiated page object know whether its output formatting should be on or off? Where is it inherited from? None of the following appear reliably correct (I could be wrong, there's a lot of combos) It could be from $thePage Page object. It could be from $pages. It could be from the back/front end context. (worst case, since then you have to explicitly call of() on every page you reference which makes a real mess of templating, requiring a temporary variable to store the page so you can make the call before using a property) It could be to do with one of the first two options at the time the referenced page is loaded, which would account for the unreliability in the case that rendering involves a process where of() is called in turn with FALSE and TRUE... Can anyone help? I guess ideally what I'm after is $thePage->setOutputFormattingOnSelfAndAllReferencedPages($bool). (Aside: yes, I'm aware of using $thePage->getFormatted() and getUnformatted() but if you have to rely on these you can't use more convenient formats like ->each() or ->get() etc.)
-
Ok, we are back in business. Stemplates (Free) is now working more cleanly with the 3rd party module. This won't be an issue again for any other module that relies on template names to function. I had to make a few other changes, but Stemplates is better for it. Here's the updated list: ✅ completely non-destructive ✅ doesn't modify your templates or fields ✅ doesn't touch system templates (admin, repeaters, etc.) ✅ doesn't alter your workflow (if anything, it simplifies it) ✅ free from manual aliases, no mapping files, no rewrite rules to maintain ✅ template files follow your renames automatically (no manual moves, no copy-paste, no backup file shuffle) ✅ third-party modules that reference template names keep working after a rename ✅ API calls using the old template name continue to work transparently ✅ every rename and every config update is logged to Setup → Logs → stemplates so you always have a full audit trail ℹ️ adds a Setup → Stemplates admin page for browsing your folders (purely additive, you can ignore it) ℹ️ writes to the database only when you rename a template, and only to keep other modules' template pickers in sync
-
Caveat 01 For transparency, I should note that the only files presenting issues were include files where the path was not absolute. The solution was to change: include("includes/get-widget.inc"); to include($config->paths->templates . "includes/get-widget.inc"); You need to do this for every include and require that uses a relative path. But, it's a one-time change, and once it's updated, the template location does not matter.
-
Hey everyone. I have a new Module in the works. It's 99.9% 75% ready for general release, but already running on my own sites for weeks. [Edit: see post about bug re. 3rd party module] If you've ever opened /site/templates/ on a project that's been running for a year, you know the feeling. 20-50 PHP with no structure, no grouping - an alphabetical avalanche. I usually get so far by namespacing all my files, but sometimes I wish for more organisation. Stemplates lets you organise your templates into folders. That's real directories on the filesystem - the way you're used to working. So, instead of leaving everything in a flat directory, you can go from this… site/templates/ ├── account-dashboard.php ├── account-billing.php ├── shipping-methods.php ├── shipping-tracking.php ├── blog-index.php ├── blog-post.php └── blog-category.php to this… site/templates/ ├── account/ │ ├── dashboard.php │ └── billing.php ├── shipping/ │ ├── methods.php │ ├── tracking.php └── blog/ ├── index.php ├── post.php └── category.php I've been running it on my own sites without issues for a while, and it takes just minutes to set up, even on a large site. Setup takes even less time if you're using AI/MCP. Even better, Stemplates is: ✅ completely non-destructive ✅ doesn't touch your database ✅ doesn't modify your templates or fields ✅ doesn't change anything in the admin UI ✅ doesn't alter your workflow ✅ free from manual aliases, no mapping files, no rewrite rules to maintain ✅ doesn't touch system templates (admin, repeaters, etc.) It also works with page classes and supports nested subfolders (50 levels tested). Understandably, I was reluctant to mess around with such a fundamental part of my sites, so a few safeguards exist... Migrate one template at a time at your own pace - no big switchover required Your existing flat templates keep working untouched, alongside any you've already moved If a file can't be found in its subfolder, ProcessWire falls back to its normal flat-folder behaviour automatically - the site doesn't break Uninstall cleanly at any time. Stemplates Free is undergoing a slight rework available now DM me for access. Stemplates Pro (coming soon) takes Stemplates even further. More soon, but honestly, Stemplates (Free) will take care of 99% of your new template -> folders world. Thanks for reading! Peter
-
PromptWire 1.7.0 is out with 4 new MCP tools, bringing the total to 40. Latest tools are listed below. I haven't 100% fully tested a site sync yet, so always back up your existing site, database and files. pw_site_compare compares your local and remote sites across pages, schema, and template/module files. Pages are matched by URL path rather than database ID, so it works reliably across environments with different auto-increment sequences. You can exclude templates (e.g. user, role, licence pages) to focus the diff on what you actually intend to deploy. pw_site_sync (my favourite) orchestrates a full deployment in one operation: compare, back up the target, enable maintenance mode, push schema, push pages with their file/image assets, push template and module files, disable maintenance. It runs in dry-run mode by default so you see the full plan before anything is touched. Scope can be narrowed to just pages, schema, or files. pw_maintenance toggles maintenance mode on local, remote, or both sites. A styled 503 page is served to visitors with appropriate Retry-After and noindex headers. Superusers and the PromptWire API bypass it, so you can verify changes and keep the agent working during a deployment. pw_backup creates database dumps (using ProcessWire's WireDatabaseBackup) and zip archives of site/templates and site/modules. You can list, restore, or delete backups from either environment. The backup directory is auto-protected with .htaccess so SQL dumps are never web-accessible. HTTPS enforcement. The API endpoint rejects plain HTTP with a 403 before the API key is checked. PROMPTWIRE_ALLOW_HTTP in config-promptwire.php bypasses this for local dev only. Autoload change. The module is now autoloaded to intercept front-end requests during maintenance mode. The cost is a single file_exists() check per page load. Documentation updated across all pages at peterknight.digital/docs/promptwire/v1/
-
There's a weird message on that module page? Anybody noticed? https://processwire.com/modules/template-preview-images/