Jump to content

Search the Community

Showing results for tags 'module'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Welcome to ProcessWire
    • News & Announcements
    • Showcase
    • Wishlist & Roadmap
  • Community Support
    • Getting Started
    • Tutorials
    • FAQs
    • General Support
    • API & Templates
    • Modules/Plugins
    • Themes and Profiles
    • Multi-Language Support
    • Security
    • Jobs
  • Off Topic
    • Pub
    • Dev Talk

Product Groups

  • Form Builder
  • ProFields
  • ProCache
  • ProMailer
  • Login Register Pro
  • ProDrafts
  • ListerPro
  • ProDevTools
  • Likes
  • Custom Development

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Location


Interests

  1. Hi everyone, I am releasing Tickets, a ProcessWire module for private customer-support conversations, staff workflows and reusable support forms. The practical problem it solves is simple: support requests often begin in a generic inbox, lose their context, and become difficult for both the customer and the team to follow. Tickets keeps that workflow inside ProcessWire, next to the accounts and content it supports, without turning private conversations into public comments. How it is used on LQRS Tickets is running on LQRS.com and its development site. The public flow shows the main value of the module: A visitor can open a private request without creating an account. The guest receives a secure access link and continues the same conversation from the website. Messages, status changes and private attachments stay together instead of being scattered across email threads. Signed-in members get a single view of their active and resolved requests. The support team works from a ProcessWire queue with assignment, priorities, internal notes, SLA state and reporting. After resolution, the customer can rate the support experience or reopen the request. For LQRS this means the Help Center remains the first place for immediate answers, while issues that require account context, a data correction, moderation review or a private file move into a trackable support workflow. What Tickets includes Authenticated and guest tickets with threaded replies. Hashed guest-access links and private attachment delivery. Statuses, priorities, assignment, routing rules, SLA targets and bulk actions. Staff-only notes, related tickets, merging and an audit trail. Reusable intake forms with validation, previews and shortcode embeds. One-way import of FormBuilder definitions into independent Tickets form drafts. Editable transactional mail templates through a selectable ProcessWire WireMail provider. Reports, CSV export, ratings, automation and retention tools. Bundled admin translations for Dutch, French, German, Italian and Spanish. Site-owned frontend Tickets owns the support domain, storage, permissions and public API. It deliberately does not overwrite the site's design. The consuming site supplies site/templates/tickets.php, controls routing below the configured support page, and composes the module output into its own frontend. A reusable form can be embedded in otherwise cacheable content: <?php namespace ProcessWire; if($modules->isInstalled('Tickets')) { /** @var Tickets $tickets */ $tickets = $modules->get('Tickets'); echo $tickets->renderFormEmbed('report-incorrect-data'); } Editors can also use: [[tickets-form:report-incorrect-data]] The API covers ticket creation, account and guest access, replies, ratings, attachments, custom forms, staff operations, reports and optional integrations. Exact signatures and authorization boundaries are documented in API.md. Privacy and operational boundaries Customer conversations and files are private; internal notes never belong in customer output. Browser writes require ProcessWire CSRF validation. Guest tokens are stored as hashes, and support routes should use private/no-store/noindex responses. Attachment access is authorized before a private filesystem path is used. Transactional delivery, inbound email, AI assistance and retention are all explicit opt-ins. Uninstall keeps ticket data by default rather than silently deleting customer records. Optional integrations Core ticketing works without additional modules. Optional integrations include WireMail providers for delivery, Resend for authenticated inbound replies, Mailbox for bounded email ingestion and SMTP reply threading, and staff-requested Squad drafts grounded by Atlas or Knowledge Base. AI drafts never send automatically. Requirements and installation ProcessWire 3.0.200 or newer. PHP 8.1 or newer. Download or clone Tickets into /site/modules/Tickets/. Refresh modules and install Tickets. Review the public path, legal links, recipients, attachment rules and optional integrations. Add the site-owned site/templates/tickets.php frontend. Grant tickets-manage and tickets-admin only to the appropriate support roles. Enable transactional delivery only after the selected mail provider has been tested. Links GitHub repository Download ZIP README Integration documentation Public API reference Live support portal on LQRS Issues and feedback I would especially appreciate feedback on the public route contract, permission boundaries and support workflows used on real ProcessWire sites.
  2. I wanted a way to chat with my Processwire site and built a Module (PW MCP) and an MCP server to connect into it. It's a private repo at the moment but it can be public if anyone finds it useful. It's basically a way to use the Cursor Chat Ui to query my site, fields, templates and content. Here's part of the readme which explains it better. What Is It? ProcessWire MCP is a bridge between ProcessWire and Cursor IDE (the AI-powered code editor). It lets you query your ProcessWire site's structure and content directly from Cursor's chat interface using natural language. Instead of writing selectors or browsing the admin, you can just ask: "What templates does this site have?" "Show me the fields on the blog-post template" "Search for pages containing 'summer'" "Find all images with 'lake' in the filename" Why I Built It Cursor can see your template files and code in the local directory, but it can't see what's actually in your ProcessWire database — which templates and fields are registered, what pages exist, or what content they contain. With ProcessWire MCP, the AI can: Query the actual database schema (not just parse template files) Look up page content by ID, path, or selector Understand field configurations (types, settings, which templates use them) Search across all text content and find files/images Get RepeaterMatrix content with type labels See file metadata (dimensions, descriptions, URLs) It's the difference between seeing $page->body in code vs. knowing what that page's body actually contains. Architecture Cursor Chat → MCP Server (Node.js) → PHP CLI → ProcessWire API The module consists of: PwMcp — A ProcessWire module with a CLI interface mcp-server — A Node.js server that speaks the Model Context Protocol The CLI can also be used standalone for quick queries from terminal. Available Commands Command Description health Check connection and get site info list-templates List all templates with field counts get-template [name] Get template details and fields list-fields List all fields with types get-field [name] Get field details and usage get-page [id\|path] Get page by ID or path with all field values query-pages [selector] Query pages using PW selectors search [query] Search content across all text fields search-files [query] Search files by name/extension export-schema Export complete site schema Example: Health Check php site/modules/PwMcp/bin/pw-mcp.php health --pretty { "status": "ok", "pwVersion": "3.0.241", "siteName": "www.example.com", "moduleLoaded": true, "counts": { "templates": 45, "fields": 72, "pages": 960 } } Example: Content Search Ask Cursor: "Search for pages containing 'summer'" { "query": "summer", "count": 5, "results": [ { "id": 1764, "title": "Lake District walks in summer", "path": "/guides/lake-district-summer/", "template": "page-guide", "matchedField": "Body", "snippet": "The Lake District offers some of the best walking trails in summer. From gentle lakeside strolls to challenging fell walks..." } ] } Example: File Search Ask Cursor: "Find images with 'lake' in the filename" { "query": "lake", "count": 5, "results": [ { "filename": "lake-windermere-sunset.jpg", "url": "/site/assets/files/1070/lake-windermere-sunset.jpg", "size": 31207, "sizeStr": "30.5 kB", "description": "Sunset over Lake Windermere", "field": "Images", "page": { "id": 1070, "title": "Lake District walks in summer", "path": "/guides/lake-district-summer/" }, "width": 500, "height": 626 } ] } Example: Get Page with All Fields Ask Cursor: "Get the page at /about/" { "id": 1050, "name": "about", "path": "/about/", "url": "/about/", "template": "basic-page", "status": 1, "statusName": "published", "parent": { "id": 1, "path": "/", "title": "Home" }, "numChildren": 5, "created": "2023-05-15T10:30:00+00:00", "modified": "2024-11-20T14:22:00+00:00", "fields": { "title": "About Us", "body": "<p>We are a team of dedicated professionals...</p>", "Images": { "_count": 2, "_files": ["team-photo.jpg", "office.jpg"] } } } Example: RepeaterMatrix Support The module fully supports RepeaterMatrix fields, returning the actual content with type labels: { "matrix": { "_count": 3, "_items": [ { "_typeId": 1, "_typeLabel": "Body", "Body": "<h2>Welcome to our guide</h2><p>This guide covers...</p>", "Images": null }, { "_typeId": 2, "_typeLabel": "FAQs", "faq_question": "What is the best time to visit?", "faq_answer": "The summer months offer the best weather for walking..." }, { "_typeId": 3, "_typeLabel": "Call to Action", "cta_title": "Plan Your Visit", "cta_link": "/contact/" } ] } } So thats the first part done and working. My next plan is to be able to 1. PULL / convert a databse page into a local text file which lists all page properties, fields, template etc 2. edit the file as a local text file 3 PUSH the text file back into PW so that the original content picks up the changes Just having fun and building something useful. Very likely there are similar solutions or better ways to handle this but this suits my workflow ATM. Cheers P
  3. Hi everyone, I’m releasing Liora, a ProcessWire module that turns unanswered searches and incomplete content pages into useful conversations — and turns those conversations into actionable editorial demand. Most site search ends in one of two places: a list of matching pages, or an empty result. That works when the visitor already knows the right words and the database contains an exact match. It is less useful when the real question is comparative, contextual or incomplete: “Which bottle fits this occasion?”, “What does this term mean?”, “What should I try next?”, or simply “I expected to find something here.” Liora adds a second path. It can answer the question, continue with follow-ups, ground the answer in public site content, and record the complete demand signal so an editor can improve the underlying website later. How it works in practice I am already using Liora on LQRS, a large ProcessWire drinks-discovery site. 1. Search no longer stops at “no results” A search such as smoky whisky from Scotland currently has no direct structured record matching the complete phrase. The normal ProcessWire results correctly say that no direct match exists. On the same page, Liora produces a concise AI overview, explains the relevant styles and regions, and links to useful internal sources such as the Scotch Whisky collection and Highlands region. The visitor can then ask a follow-up without starting again. This is important: Liora does not replace the deterministic search results or pretend that a generated answer is a canonical database record. The page shows both layers clearly — a conversational overview and the actual structured matches. 2. A content page can answer the next question At the bottom of selected collection and discovery pages, Liora appears as an “Ask about this collection” surface. The widget knows the current ProcessWire page and can use relevant Atlas excerpts and published Vox discussions when those integrations are enabled. A static collection therefore becomes a useful starting point for questions about selection, comparison, terminology or pairings, while the original page remains the source of truth. 3. A 404 becomes a recovery path On the LQRS 404 page, Liora asks what the visitor expected to find. It can help locate a product, recipe, article or guide instead of leaving the visitor at a dead end. 4. Questions become an editorial backlog Every tracked frontend conversation appears in Setup → Liora Insights. Editors can see repeated unmet searches, the source page, referrer, conversation history, status, model, response time, token usage, cache state, retrieval sources and failures. This is the part I find most useful. The generated answer is immediate help for one visitor; the collected demand shows what the site should fix for everyone. Repeated questions can become better structured data, a missing product page, a clearer explanation, a new guide, improved navigation or a search synonym. What Liora includes A reusable frontend conversation widget and InputfieldLiora. Normal JSON responses and real-time streamed responses. One tracked Thread per visitor conversation with chronological messages. Follow-up continuity that preserves recent constraints. Automatic page, source and referrer attribution. Setup → Liora Insights for review, diagnostics and editorial status. Repeated unmet-demand reporting. Optional Atlas retrieval from indexed public site content. Optional published Vox reviews, questions, replies and discussions. Optional live public search through compatible Squad providers. Optional coarse GeoIP enrichment. Validated light and dark themes. Safe Markdown rendering and verified same-site links. Localized widget text and ready-made language presets. A tracked JSON endpoint for completely custom frontends. Public PHP APIs for direct application use. Architecture Liora deliberately does not store provider credentials or implement low-level AI transport. That remains the responsibility of Squad. Liora owns conversations, tracking, retrieval orchestration, the widget and Insights. Squad owns providers, credentials, model discovery, requests and streaming transport. Atlas can supply excerpts from indexed public site content. Vox can supply published community evidence attached to relevant pages. ProcessWire remains responsible for pages, permissions, sessions, localization and persistence. Atlas, Vox, GeoIP and live web search are optional. Liora works with Squad alone and fails back cleanly when an optional context source is unavailable. Basic integration <?php namespace ProcessWire; if($modules->isInstalled('Liora')) { $liora = $modules->get('Liora'); echo $liora->renderWidget([ 'context' => $page->template->name, 'sourceUrl' => $page->url, 'pageId' => $page->id, 'heading' => 'Still looking? Ask Liora', 'theme' => 'default', ]); } The tracked endpoint itself can remain deliberately thin: <?php namespace ProcessWire; $modules->get('Liora')->handleEndpoint(); The consuming site decides where the widget belongs. Liora never inserts itself automatically and does not take over routes, content models or publishing decisions. Privacy and safety Provider credentials remain in Squad. Raw model HTML is never trusted. Atlas excerpts, community content and web results are treated as untrusted reference material. Same-site links are validated; external destinations can be restricted. CSRF protection, rate limits and conversation ownership checks apply to the tracked endpoint. Liora stores a hashed session owner, not a plaintext session identifier. Raw IP addresses and browser user agents are not stored. Conversation review and destructive actions use separate ProcessWire permissions. Stored conversations are preserved on uninstall by default unless destructive uninstall is explicitly enabled. Requirements ProcessWire 3.0.210 or newer PHP 8.1 or newer An installed and configured Squad module A ProcessWire endpoint page for tracked frontend conversations Installation Copy the Liora directory to /site/modules/Liora/. Refresh modules in ProcessWire and install Liora. Configure at least one active provider in Squad. Review the model, prompt, widget, retrieval, privacy and retention settings. Create or reuse the JSON endpoint page and keep its URL synchronized with Liora configuration. Add the widget, Inputfield or custom frontend only where it belongs in the site architecture. Live examples LQRS search with an AI overview: https://lqrs.com/search/?q=smoky%20whisky%20from%20Scotland Page-aware collection widget: https://lqrs.com/collection/best-drinks-of-france/ Dedicated conversation page: https://lqrs.com/ai/ Links GitHub: https://github.com/mxmsmnv/Liora Download ZIP: https://github.com/mxmsmnv/Liora/archive/refs/heads/main.zip README: https://github.com/mxmsmnv/Liora/blob/main/README.md API documentation: https://github.com/mxmsmnv/Liora/blob/main/API.md Integration guide: https://github.com/mxmsmnv/Liora/blob/main/docs/INTEGRATION.md Issues and support: https://github.com/mxmsmnv/Liora/issues I would especially appreciate feedback about where this pattern is useful outside search: documentation, support, directories, product catalogues, knowledge bases and editorial sites — and how you would turn real visitor questions into better ProcessWire content.
  4. Hi everyone, I’m releasing Lumen, a ProcessWire module for managing Cloudflare Stream video from the page editor and the ProcessWire admin. Lumen adds a dedicated video Fieldtype and Inputfield, handles direct and resumable uploads, follows Cloudflare processing status, and exposes playback, thumbnails and metadata through familiar ProcessWire APIs. What Lumen does Adds a Cloudflare Stream Files Fieldtype and Inputfield. Supports direct uploads and resumable TUS uploads. Stores Stream status, duration, dimensions, category, tags, poster, subtitles, trim points, linked page and view count. Provides HLS URLs, responsive iframe embeds, thumbnails, posters and previews. Supports public playback and private playback with signed Stream tokens. Detects portrait, landscape, square and unknown video orientation. Identifies ready portrait videos that fit a configurable short-form duration. Refreshes pending Stream metadata through bounded LazyCron jobs. Includes local-storage mode for development without a Cloudflare account. Protects expiring signed playback URLs when CloudCache is installed. Provides public upload and metadata APIs for integrations with other modules. Embeds videos in formatted text through [[lumen:...]] shortcodes. Admin workspace Lumen adds Setup → Lumen, where editors can upload videos, browse and filter the library, refresh processing status, inspect metadata, copy embeds and Stream URLs, estimate stored and delivered minutes, configure playback and review diagnostics. The field itself can be added to any required template, so video remains part of the normal ProcessWire content model rather than a separate media system. Pagefile API <?php namespace ProcessWire; if($modules->isInstalled('Lumen')) { $lumen = $modules->get('Lumen'); echo $video->streamEmbedResponsive(); $thumbnail = $video->streamThumbnail(12); $poster = $video->streamPoster(); $ready = $video->streamReady(); $orientation = $lumen->streamOrientation($video); } Trusted integrations can also attach uploaded or local files: $video = $lumen->attachUploadedVideo( $page, 'video', $_FILES['video'], 1024 * 1024 * 1024 ); $video = $lumen->attachLocalVideo($page, 'video', $sourcePath); Textformatter The included Textformatter supports: [[lumen:video_uid]] [[lumen:page_id.field_name]] [[lumen:page_id.field_name:thumb]] Requirements ProcessWire 3.0.255 or newer PHP cURL A Cloudflare account with Stream enabled, unless local-storage mode is used for development Installation Copy the Lumen directory to /site/modules/Lumen/. Refresh modules in the ProcessWire admin and install Lumen. Enable Cloudflare Stream for the account. Create an API token with Stream:Edit permission. Save the Account ID and token in Modules → Configure → Lumen. Open Setup → Lumen and refresh the connection status. Create a Cloudflare Stream Files field and add it to the required templates. Links GitHub: https://github.com/mxmsmnv/Lumen Issues and support: https://github.com/mxmsmnv/Lumen/issues Feedback about field behavior, upload workflows, signed playback and the admin experience is very welcome.
  5. (once again I was surprised to see a work of mine pop up in the newsletter, this time without even listing the module on PW modules website. Thx @teppo !) FieldtypeQRCode Github: https://github.com/eprcstudio/FieldtypeQRCode Modules directory: https://processwire.com/modules/fieldtype-qrcode/ A simple fieldtype generating a QR Code from the public URL of the page, and more. Using the PHP library QR Code Generator by Kazuhiko Arase. Options In the field’s Details tab you can change between .gif or .svg formats. If you select .svg you will have the option to directly output the markup instead of a base64 image. SVG is the default. You can also change what is used to generate the QR code and even have several sources. The accepted sources (separated by a comma) are: httpUrl, editUrl, or the name of any text/URL/file/image field. If LanguageSupport is installed the compatible sources (httpUrl, text field, ...) will return as many QR codes as there are languages. Note however that when outputting on the front-end, only the languages visible to the user will be generated. Additionally you can set the error correction level which allows to better recover lost data in case of visual damage. This is also used when covering part of a QR code with a logo. There are four levels of correction: L, with 7% of potential data recovery M, with 15% of potential data recovery Q, with 25% of potential data recovery and H, with 30% of potential data recovery Since 1.2.0, the appearance of the QR code can be adapted to your likings with the ability to set a module’s (one of the small square) size in pixels, change the foreground and background colors, or even set the background to be transparent. Formatting Unformatted value When using $page->getUnformatted("qrcode_field") it returns an array with the following structure: [ [ "label" => string, // label used in the admin "qr" => string, // the qrcode image "raw" => string, // the raw qrcode image (in base64, except if svg+markup) "source" => string, // the source, as defined in the configuration "text" => string // and the text used to generate the qrcode ], ... ] Formatted value The formatted value is an <img>/<svg> (or several right next to each other). There is no other markup. Should you need the same markup as in the admin you could use: $field = $fields->get("qrcode_field"); $field->type->markupValue($page, $field, $page->getUnformatted("qrcode_field")); But it’s a bit cumbersome, plus you need to import the FieldtypeQRCode's css/js. Best is to make your own markup using the unformatted value. Static QR code generator You can call FieldtypeQRCode::generateQRCode (or FieldtypeQRCode::generateQRCode) to generate any QR code you want. Its arguments are: string $text bool|array $svg Generate the QR code as svg instead of gif? (default=true) bool $markup If svg, output its markup instead of a base64? (default=false) string $recoveryLevel Set error correction level (default="L") If you pass an array instead of a boolean for svg you can set the following options: [ "svg" => true, "markup" => false, "recoveryLevel" => "L", "size" => 2, "foreground" => "#000000", "background" => "#FFFFFF", "transparent" => false, ] Hooks Please have a look at the source code for more details about the hookable functions. Examples $wire->addHookAfter("FieldtypeQRCode::getQRText", function($event) { $page = $event->arguments("page"); $event->return = $page->title; // or could be: $event->return = "Your custom text"; }); $wire->addHookAfter("FieldtypeQRCode::generateQRCodes", function($event) { $qrcodes = $event->return; // keep everything except the QR codes generated from editUrl foreach($qrcodes as $key => &$qrcode) { if($qrcode["source"] === "editUrl") { unset($qrcodes[$key]); } } unset($qrcode); $event->return = $qrcodes; }); Generating multiple QR code during a page render can be expensive. Since v2.0.0, you can use the following hooks to cache the output and speed things up on subsequent requests: $wire->addHookBefore("FieldtypeQRCode::generateQRCodes", function(HookEvent $event) { /** @var Field $field */ $field = $event->arguments("field"); /** @var Page $page */ $page = $event->arguments("page"); $qrcodes = $page->meta()->get("qrcodes-{$field->name}"); if(!empty($qrcodes)) { $event->return = json_decode($qrcodes, true); $event->replace = true; } }); $wire->addHookAfter("FieldtypeQRCode::generateQRCodes", function(HookEvent $event) { /** @var Field $field */ $field = $event->arguments("field"); /** @var Page $page */ $page = $event->arguments("page"); $page->meta()->set("qrcodes-{$field->name}", json_encode($event->return)); }); $wire->addHookAfter("Page::saved", function(HookEvent $event) { /** @var Page $page */ $page = $event->object; foreach($page->fields->find("type=FieldtypeQRCode") as $field) { $page->meta()->remove("qrcodes-{$field->name}"); } }); Note Depending on the level of correction set and the type of characters encoded in the QR code, the maximum size allowed for a QR code can vary. It is adviced to set a maximum character count on textareas or any relevant Inputfields Recovery Level Numeric Alphanumeric Byte Kanji L (7%) 7089 4296 2953 1817 M (15%) 5596 3391 2331 1435 Q (25%) 3993 2420 1663 1024 H (30%) 3057 1852 1273 784
  6. Hi everyone, I’m releasing Resend, a ProcessWire module for transactional email, audience management and delivery operations through the Resend API. It works as a regular ProcessWire WireMail provider for everyday site email, while also exposing Resend-specific domains, contacts, segments, topics, templates, broadcasts, webhooks and delivery diagnostics inside the ProcessWire admin. What Resend does Sends ProcessWire mail through the Resend API as a WireMail provider. Supports transactional and batch sends, scheduling, cancellation, idempotency keys and tags. Manages sending domains and provides DNS setup guidance for SPF, MX, TXT and CNAME records. Manages contacts, segments, contact properties and topic subscriptions. Creates, edits, publishes and duplicates templates. Creates, edits, sends and schedules broadcasts. Receives and verifies Resend webhooks at /resend-webhook/. Stores webhook events locally for inspection and site automation. Lists sent and received email, attachments, API logs and delivery signals. Includes safe simulator sends using resend.dev recipients. Encrypts API keys and webhook secrets in a dedicated settings table. Bundles ProcessWire language files for English, French, German and Spanish. Includes a CLI for diagnostics and scripted operations. Normal ProcessWire mail API Existing site code can continue to use wireMail(): $mail = wireMail(); $mail->to('person@example.com') ->from('Site <hello@example.com>') ->subject('Thanks for your request') ->bodyHTML('<p>We received your request.</p>') ->send(); Resend-specific options are available when needed: $mail = wireMail(); $mail->to('person@example.com') ->subject('Welcome') ->bodyHTML('<p>Hello</p>'); $mail->scheduledAt('in 1 hour'); $mail->addTag('source', 'website'); $mail->idempotencyKey('welcome-' . $page->id); $mail->send(); Modules that discover providers by a WireMail* class name can select the included WireMail Resend compatibility module. Requirements ProcessWire 3.0.184 or newer PHP 8.1 or newer A Resend account A verified sending domain for production email Installation Copy the Resend directory to /site/modules/Resend/. Refresh modules in the ProcessWire admin. Install Resend; ProcessResend, ResendWebhooks and WireMailResend are installed automatically. Add the Resend API key and default sender in module settings. Open Setup → Resend and add or verify a sending domain. Use the simulator test screen before sending to real recipients. Screenshots Links GitHub: https://github.com/mxmsmnv/Resend Release 1.0.1: https://github.com/mxmsmnv/Resend/releases/tag/v1.0.1 Documentation: https://github.com/mxmsmnv/Resend/blob/main/DOCUMENTATION.md Issues and support: https://github.com/mxmsmnv/Resend/issues Feedback about WireMail compatibility, delivery workflows and the admin experience is welcome.
  7. Hi everyone, I’m releasing Radar, a content-intelligence and content-operations module for ProcessWire. Radar helps you inspect and improve content across a ProcessWire site without silently changing published pages. It starts with deterministic scans, can add evidence-backed research and optional AI interpretation, and produces reviewable drafts before anything is written. What Radar does Maps ProcessWire templates and fields to reusable Content Types. Scans individual pages, sections, templates, Content Types or a complete site. Includes focused quality, freshness, accessibility-content, conversion, duplicate, relation and taxonomy scans. Finds missing mapped content, weak structure, coverage gaps, duplicates and broken content relationships. Supports internal, URL-based, competitor, official-source, catalog and optional Atlas knowledge-base research. Generates field, multi-field, rewrite, summary, CTA, FAQ, metadata, taxonomy, relation and translation proposals. Stores reports and compares compatible snapshots. Provides an editorial review queue with author, reviewer, status and timestamps. Includes admin workspaces, diagnostics and deterministic CLI commands. Bundles French, German and Spanish admin translations; English is the source language. Safe workflow Deterministic scans are read-only. AI generation creates a proposal and does not silently modify a page. Before applying a draft, Radar shows the current and proposed values and checks ProcessWire permissions and whether the source content has changed since the draft was created. AI is optional. The core audit, quality, conversion, duplicate, relation and taxonomy workflows work deterministically. Requirements ProcessWire 3.0.244 or newer PHP 8.3 or newer Squad for optional AI analysis, research interpretation and generation Atlas only for optional knowledge-base research Installation Copy the Radar directory to /site/modules/Radar/. Refresh modules in the ProcessWire admin. Install Radar; the companion ProcessRadar admin module is installed automatically. Open Setup → Radar → Diagnostics. Define or confirm Content Type field mappings before running broader scans. Screenshots Basic API example $radar = $modules->get('Radar'); $pageScan = $radar->scanPage($page); $siteScan = $radar->scanSite([ 'limit' => 1000, 'relationScan' => true, ]); // This creates a proposal; it does not modify the page. $result = $radar->generateField($page, 'summary', [ 'instruction' => 'Explain the value proposition clearly.', ]); The repository includes detailed administrator, API, CLI, safety and integration documentation. Links GitHub: https://github.com/mxmsmnv/Radar Feedback and real-world content-model examples are welcome.
  8. Hi everyone, Here's a new module that I have been meaning to build for a long time. http://modules.processwire.com/modules/process-admin-actions/ https://github.com/adrianbj/ProcessAdminActions What does it do? Do you have a bunch of admin snippets laying around, or do you recreate from them from scratch every time you need them, or do you try to find where you saw them in the forums, or on the ProcessWire Recipes site? Admin Actions lets you quickly create actions in the admin that you can use over and over and even make available to your site editors (permissions for each action are assigned to roles separately so you have full control over who has access to which actions). Included Actions It comes bundled with several actions and I will be adding more over time (and hopefully I'll get some PRs from you guys too). You can browse and sort and if you have @tpr's Admin on Steroid's datatables filter feature, you can even filter based on the content of all columns. The headliner action included with the module is: PageTable To RepeaterMatrix which fully converts an existing (and populated) PageTable field to either a Repeater or RepeaterMatrix field. This is a huge timesaver if you have an existing site that makes heavy use of PageTable fields and you would like to give the clients the improved interface of RepeaterMatrix. Copy Content To Other Field This action copies the content from one field to another field on all pages that use the selected template. Copy Field Content To Other Page Copies the content from a field on one page to the same field on another page. Copy Repeater Items To Other Page Add the items from a Repeater field on one page to the same field on another page. Copy Table Field Rows To Other Page Add the rows from a Table field on one page to the same field on another page. Create Users Batcher Allows you to batch create users. This module requires the Email New User module and it should be configured to generate a password automatically. Delete Unused Fields Deletes fields that are not used by any templates. Delete Unused Templates Deletes templates that are not used by any pages. Email Batcher Lets you email multiple addresses at once. Field Set Or Search And Replace Set field values, or search and replace text in field values from a filtered selection of pages and fields. FTP Files to Page Add files/images from a folder to a selected page. Page Active Languages Batcher Lets you enable or disable active status of multiple languages on multiple pages at once. Page Manipulator Uses an InputfieldSelector to query pages and then allows batch actions on the matched pages. Page Table To Repeater Matrix Fully converts an existing (and populated) PageTable field to either a Repeater or RepeaterMatrix field. Template Fields Batcher Lets you add or remove multiple fields from multiple templates at once. Template Roles Batcher Lets you add or remove access permissions, for multiple roles and multiple templates at once. User Roles Permissions Batcher Lets you add or remove permissions for multiple roles, or roles for multiple users at once. Creating a New Action If you create a new action that you think others would find useful, please add it to the actions subfolder of this module and submit a PR. If you think it is only useful for you, place it in /site/templates/AdminActions/ so that it doesn't get lost on module updates. A new action file can be as simple as this: <?php namespace ProcessWire; class UnpublishAboutPage extends ProcessAdminActions { protected function executeAction() { $p = $this->pages->get('/about/'); $p->addStatus(Page::statusUnpublished); $p->save(); return true; } } Each action: class must extend "ProcessAdminActions" and the filename must match the class name and end in ".action.php" like: UnpublishAboutPage.action.php the action method must be: executeAction() As you can see there are only a few lines needed to wrap the actual API call, so it's really worth the small extra effort to make an action. Obviously that example action is not very useful. Here is another more useful one that is included with the module. It includes $description, $notes, and $author variables which are used in the module table selector interface. It also makes use of the defineOptions() method which builds the input fields used to gather the required options before running the action. <?php namespace ProcessWire; class DeleteUnusedFields extends ProcessAdminActions { protected $description = 'Deletes fields that are not used by any templates.'; protected $notes = 'Shows a list of unused fields with checkboxes to select those to delete.'; protected $author = 'Adrian Jones'; protected $authorLinks = array( 'pwforum' => '985-adrian', 'pwdirectory' => 'adrian-jones', 'github' => 'adrianbj', ); protected function defineOptions() { $fieldOptions = array(); foreach($this->fields as $field) { if ($field->flags & Field::flagSystem || $field->flags & Field::flagPermanent) continue; if(count($field->getFieldgroups()) === 0) $fieldOptions[$field->id] = $field->label ? $field->label . ' (' . $field->name . ')' : $field->name; } return array( array( 'name' => 'fields', 'label' => 'Fields', 'description' => 'Select the fields you want to delete', 'notes' => 'Note that all fields listed are not used by any templates and should therefore be safe to delete', 'type' => 'checkboxes', 'options' => $fieldOptions, 'required' => true ) ); } protected function executeAction($options) { $count = 0; foreach($options['fields'] as $field) { $f = $this->fields->get($field); $this->fields->delete($f); $count++; } $this->successMessage = $count . ' field' . _n('', 's', $count) . ' ' . _n('was', 'were', $count) . ' successfully deleted'; return true; } } This defineOptions() method builds input fields that look like this: Finally we use $options array in the executeAction() method to get the values entered into those options fields to run the API script to remove the checked fields. There is one additional method that I didn't outline called: checkRequirements() - you can see it in action in the PageTableToRepeaterMatrix action. You can use this to prevent the action from running if certain requirements are not met. At the end of the executeAction() method you can populate $this->successMessage, or $this->failureMessage which will be returned after the action has finished. Populating options via URL parameters You can also populate the option parameters via URL parameters. You should split multiple values with a “|” character. You can either just pre-populate options: http://mysite.dev/processwire/setup/admin-actions/options?action=TemplateFieldsBatcher&templates=29|56&fields=219&addOrRemove=add or you can execute immediately: http://mysite.dev/processwire/setup/admin-actions/execute?action=TemplateFieldsBatcher&templates=29|56&fields=219&addOrRemove=add Note the “options” vs “execute” as the last path before the parameters. Automatic Backup / Restore Before any action is executed, a full database backup is automatically made. You have a few options to run a restore if needed: Follow the Restore link that is presented after an action completes Use the "Restore" submenu: Setup > Admin Actions > Restore Move the restoredb.php file from the /site/assets/cache/AdminActions/ folder to the root of your site and load in the browser Manually restore using the AdminActionsBackup.sql file in the /site/assets/cache/AdminActions/ folder I think all these features make it very easy to create custom admin data manipulation methods that can be shared with others and executed using a simple interface without needing to build a full Process Module custom interface from scratch. I also hope it will reduce the barriers for new ProcessWire users to create custom admin functionality. Please let me know what you think, especially if you have ideas for improving the interface, or the way actions are defined.
  9. FieldtypeMapMarker Module for ProcessWire 2.1+ This Fieldtype for ProcessWire 2.1+ holds an address or location name, and automatically geocodes the address to latitude/longitude using Google Maps API. This Fieldtype was also created to serve as an example of creating a custom Fieldtype and Inputfield that contains multiple pieces of data. Download at: https://github.com/r...ldtypeMapMarker How to Use To use, install FieldtypeMapMarker like you would any other module (install instructions: http://processwire.c...wnload/modules/). Then create a new field that uses it. Add that field to a template and edit a page using that template. Enter an address, place or location of any sort into the 'Address' field and hit Save. For example, Google Maps will geocode any of these: 125 E. Court Square, Decatur, GA 30030 Atlanta, GA Disney World The address will be converted into latitude/longitude coordinates when you save the page. The field will also show a map of the location once it has the coordinates. On the front end, you can utilize this data for your own Google Maps (or anything else that you might need latitude/longitude for). Lets assume that your field is called 'marker'. Here is how you would access the components of it from the API: <?php echo $page->marker->address; // outputs the address you entered echo $page->marker->lat; // outputs the latitude echo $page->marker->lng; // outputs the longitude Of course, this Fieldtype works without it's Inputfield too. To geocode an address from the API, all you need to do is set or change the 'address' component of your field, i.e. <?php $page->marker->address = 'Disney Land'; $page->save(); // lat/lng will now be updated to Disney Land's lat/lng
  10. Hi everyone, I'd like to share a new ImageSizerEngine module I've been working on: Intervention Image Sizer, which uses Intervention Image v4 as the underlying image manipulation library instead of GD/Imagick being called directly. It's a drop-in replacement: once installed, $page->image->size(), crops, WebP variations etc. all keep working exactly as before, no template changes required. Credit where it's due: I got the idea after reading this post about Intervention Image Engine. That module takes its own approach (own responsive-image handling on top of Intervention Image). For this one, I wanted a straightforward ImageSizerEngine that plugs directly into ProcessWire's built-in image sizing. So it extends the core ImageSizerEngine base class and implements its abstract methods (processResize, processRotate, processFlip, etc.) directly against Intervention Image v4, rather than building on top of that other module. Why another ImageSizerEngine? Intervention Image v4 gives you one consistent API on top of three different backends: GD, Imagick, and libvips. This module lets you pick the driver per installation from the module settings, so you can: - Stick with GD if that's all you have (default, always available, zero extra setup). - Switch to Imagick if it's installed and you need it for something specific. - Switch to libvips for significantly lower memory usage and faster processing on large images_ useful if you're dealing with high-res uploads or a busy image-heavy site. - Use Animated GIF support everywhere Features - Selectable driver: GD, Imagick, or libvips (auto-detected, the dropdown only shows drivers that are actually available on your server). - Extended format support with Imagick/libvips: AVIF, TIFF, HEIC, HEIF, in addition to the usual JPG, PNG, GIF, WEBP. - Full support for the standard ImageSizerEngine options: auto-orientation (EXIF), rotate, flip, cropping (including focus-zoom cropping), sharpening. - Optional WebP sibling generation (webpAdd / webpOnly). - Greyscale and sepia conversion. - Optional temporary memory_limit bump during resize operations: can be restricted to animated images only. - Optional debug logging of each resize step to Setup > Logs > intervention-image. - Module config screen shows GD/Imagick/libvips availability, FFI status, and current PHP memory_limit at a glance. Requirements - PHP >= 8.3 - GD extension (default/fallback driver) - Optional: imagick PHP extension for the Imagick driver - Optional: ffi extension (with ffi.enable = true) plus libvips installed, for the libvips driver Installation Easiest way: grab the release zip from the Releases page: it ships with vendor/ bundled in, no composer step needed. Extract into site/modules/ and install from Modules > Refresh. To build from source instead: clone into site/modules/ImageSizerEngineIntervention and run composer install before installing the module. Download / GitHub: GitHub Repo Feedback welcome Still fairly fresh, so I'd appreciate any testing/feedback, especially around the libvips driver, since FFI setup varies a lot between hosting environments. Bug reports and PRs welcome here or on GitHub.
  11. Hi everyone, I’m happy to share NativeAnalytics, a native first-party analytics module for ProcessWire. The module is now available in the ProcessWire modules directory: https://processwire.com/modules/native-analytics/ NativeAnalytics provides a useful analytics dashboard directly inside the ProcessWire admin, without relying on external analytics platforms, third-party scripts or external APIs. All analytics data is stored locally in your ProcessWire installation, which makes it a good fit for projects where you want a simpler, more self-contained analytics solution. The module currently tracks and displays: page views unique visitors sessions current visitors top pages referrers devices and browsers 404 hits engagement events such as form submits, downloads, tel/mail clicks, outbound clicks and custom CTA events It also includes: charts and trend views comparison between periods custom date range filtering page-level analytics inside the page edit screen optional monthly email reports optional PDF report attachments exports to CSV, PDF and DOCX helper examples and a small snippet generator for custom event tracking New in the latest version: Goals and conversion tracking event-based goals, for example form submits, CTA clicks, downloads or tel/mail clicks page/path-based goals, for example thank-you pages or booking confirmation pages conversion rate reporting based on sessions and unique visitors a dedicated Goals dashboard with goal cards, goal trends and goal overview easier goal setup with helper text, quick presets and suggestions from already tracked events and pages daily aggregate tables for events and goals raw event retention setting additional database indexes and cleanup helpers for larger datasets There are also several privacy and consent-related options: optional cookie-less visitor/session mode consent-based tracking helper functions for custom consent integrations optional PrivacyWire localStorage consent helper support cleaner behaviour when global tracking is disabled The reason I built this module was that I wanted something that feels natural inside ProcessWire itself, instead of embedding another analytics service into the admin. For many sites, it can be useful to have core traffic, engagement and conversion data available right where content is managed. Goal tracking was added because several users asked for a simple way to measure important actions without having to fight with external analytics tools. For example, you can now create a goal for a contact form submit, a CTA button click, a file download or a visit to a thank-you page, and then see conversions and conversion rates directly in the ProcessWire admin. A small note about very large datasets: NativeAnalytics includes retention settings, daily aggregate tables and cleanup tools, and the latest version improves this further for events and goals. For very high-traffic sites, I still recommend using sensible raw data retention and keeping long-term reporting based on aggregated data. I do not want to overclaim without real long-term benchmarks on extremely large datasets, so feedback from larger installations is very welcome. ! If you tested one of the earlier development versions named PW Native Analytics, I recommend uninstalling that old test version first and installing NativeAnalytics as a fresh module, because the module name and structure changed during development. Multi-site analytics is not included yet, but it is something I am looking into. It would need proper per-site separation in the stored analytics data, so I want to approach that carefully rather than adding a quick workaround. Feedback, bug reports and suggestions are very welcome. Get it here: https://processwire.com/modules/native-analytics/ Enjoy! If you find NativeAnalytics useful and would like to support further development, maintenance and testing, a small donation is always appreciated. The module will remain free, but support helps me spend more time improving it and adding new features. DONATE
  12. Hi everyone, I'd like to share Cookie, a consent management module I've been building — a consent banner, preferences window, server-side auto-blocking of trackers, and an interactive visual builder for styling the whole thing without touching CSS. GitHub: https://github.com/mxmsmnv/Cookie Demo (Design Studio): https://drive.google.com/file/d/1u5nSmBogZJd8FF5vVZ_R2CABkSAZvXl2/view Why Most consent solutions I looked at made you choose: either you get compliance (trackers actually blocked before consent) or you get design control (colors, layout, icon placement) — rarely both without editing CSS/JS by hand. Cookie tries to give you both. What it does Consent-first by default. Known trackers and embeds (GTM, Google Analytics, Yandex Metrika, Meta Pixel, Hotjar, Clarity, DoubleClick, TikTok, YouTube, Vimeo, Google Maps and more) are neutralized server-side, in the rendered page, before it reaches the browser. Two consent models: opt-in (GDPR/ePrivacy, UK GDPR/PECR, LGPD, Law 25, POPIA, KVKK) and opt-out (CCPA/CPRA and other US state laws), plus Global Privacy Control support, and a geo mode that picks the model automatically by visitor country. Category-based blocking of scripts, iframes, images and video, with placeholders and multi-category requirements. A visual builder (Setup > Cookie — "Design Studio"): live-preview layout, colors, fonts, radius, shadows, spacing. 50 color presets, 25 icon-color presets, 18 dark-theme presets. A floating settings icon with 7 built-in choices, adjustable shape/size/position/color/shadow, including a transparent icon-only mode. A dark theme with its own live-edited color set. A services catalog + cookie policy generator. Google Consent Mode v2, consent expiry/versioning, JS API, CustomEvents. Optional consent log with CSV export and a small statistics dashboard. Everything is hookable, and it's multi-language out of the box with per-language text targeting. Basic usage <script type="text/plain" data-consent="statistics" src="https://example.com/analytics.js"></script> $wire->addHookAfter('Cookie::allowCategory', function($e) { if ($e->arguments(0) === 'marketing') $e->return = false; }); Installation Copy to /site/modules/, install, configure texts/categories in module settings, design the widget in Setup > Cookie. Requires ProcessWire 3.0.244+ and PHP 8.2+. MPL-2.0 licensed. Full docs and hooks reference: README. This is the 1.0.0 release — feedback and bug reports welcome! GitHub: https://github.com/mxmsmnv/Cookie Demo (Design Studio): https://drive.google.com/file/d/1u5nSmBogZJd8FF5vVZ_R2CABkSAZvXl2/view
  13. This module extends WireMail base class, integrating the PHPMailer mailing library into ProcessWire. Module Directory - Githup repo
  14. Hey folks, fun fact: this module was already featured in this week’s ProcessWire Weekly – even before we managed to post it here in the forum. So, here we are, finally giving it a proper introduction! 😅 TL;DR: This module connects Stripe Payment Links with ProcessWire and provides a simple checkout integration for sites that don’t need a full shop. 🎯 ✅ Drop a Stripe buy button anywhere ✅ Redirect back to PW thank-you or delivery pages ✅ Buyers get accounts, purchases are logged, access is granted ✅ Access mails are sent automatically ✴️ New in v 1.0.7: Sync existing purchases and buyers from Stripe to PW with test/write option ✴️ New in v 1.0.8: Full Stripe subscription support with real-time webhook updates (cancel, pause, resume, renew) and smarter access control logic ✴️ New in v 1.0.10: Notify existing buyers and update purchases when products gain gated content. ✴️ New in v 1.0.11: More flexible Access mails ✴️ New in v 1.0.14: Create and send "Magic Links" (access links) to customers for products they've already purchased. ✴️ New in v 1.0.23: Give Free Product Access to customers. ✴️ New in v 1.0.25: Merge Accounts of customers who purchased with different mail addresses. ✴️ New in v 1.1.0: Electronic withdrawal function (modal flow + audit log) ✴️ New in v 1.2.0: Order-confirmation mail with consumer-rights block – withdrawal instructions for redeemable products, waiver acknowledgment for digital-immediate products. ✴️ New in v 1.3.0: Redirect-independent purchase recording, reworked login & access possibilities, impersonation ("log in as user"), freebies (lead capture). First things first: What are Stripe Payment Links? Stripe Payment Links are basically hosted checkout pages that you can create directly in the Stripe Dashboard – no coding required. You define a product (or multiple line items) in Stripe. Stripe gives you a unique URL (the “Payment Link”). You can drop this URL behind any button, on any landing page, newsletter, or social media bio. When a customer clicks the link, they’re taken to a secure Stripe Checkout page (PCI compliant, supports all major payment methods, Apple Pay, etc.). After payment, Stripe redirects them back to your success URL. Super simple. But… on its own, Stripe has no idea about your ProcessWire site, your users, or your gated content. That’s where this module jumps in. 🚀 Why another payment module? We at frameless Media often work on small client projects where setting up a full e-commerce shop would be complete overkill. Think: Coaches selling a few courses or workshops Businesses offering a handful of digital products or subscriptions Creators who just need a buy button on a landing page Stripe Payment Links are perfect for this. But: ProcessWire on its own doesn’t handle redirects, user handling, or gated delivery pages. So we built StripePaymentLinks – a lightweight drop-in module to connect Stripe with PW. What it does Handles the redirect back from Stripe Checkout that contains the session id Creates or updates the buyer’s user account Records purchases in a repeater field Manages access to “delivery pages” (only available after purchase) Auto-sends access mails (configurable: never / new users only / always) Provides Bootstrap-based modals for login, password reset, set-password Usage examples Example 1: Sales page + delivery page Sales page has a “Buy now” button (Stripe Payment Link). After checkout, the user is redirected to the delivery page, which is access-protected. → Module logs them in, grants access, and if they’re new: a set-password modal pops up. → An access mail with product links is sent. Example 2: Product without a delivery page Some products don’t need protected pages (e.g. a consulting slot or voucher). → The success redirect goes to a generic thank-you page. → The module shows an access summary block with purchased products and sends the mail. Example 3: Mixed purchase (thank-you + delivery page) A checkout with multiple items: e.g. a “simple product” plus an addon that has its own delivery page. → Thank-you page shows the addon link(s). → The access mail lists all purchased products. Source & License The module is open-source under the MIT License. 👉 GitHub: https://github.com/frameless-at/StripePaymentLinks 👉 ProcessWire modules directory: https://processwire.com/modules/stripe-payment-links/ So yes: if you or your clients just need a few low-barrier buy buttons, not a full-blown webshop, this might be the module you’ve been looking for. If needed we can provide some screenshots and visual examples next week 😉 Happy to hear your thoughts, ideas, and testing feedback! Cheers, Mike
  15. This module for ProcessWire sends a notification email for each failed login attempt. Similar modules exists already in the module directory of ProcessWire. However, this module is designed to notify, even if specified user doesn't exist. Settings The settings for this module are located in the menu Modules=>Configure=>LoginFailNotifier. Notification email Specifies the email address to which the notification emails should be sent. Email subject Specifies the subject line for the notification email. Post variables Specifies the $_POST variables to be included in the notification email. Each variable must be separated by a comma. For example: login_name,login_pass Server variables Specifies the $_SERVER variables to be included in the notification email. Each variable must be separated by a comma. For example: REMOTE_ADDR,HTTP_USER_AGENT Link to ProcessWire module directory: https://processwire.com/modules/login-fail-notifier/ Link to github.com: https://github.com/techcnet/LoginFailNotifier
  16. Hi everyone I've started a new module called SEO NEO It's a new SEO module built for today's SEO, on today's ProcessWire. I hadn’t planned another module, but I keep returning to the same niggling thought: SEO is too important to our clients' sites (and businesses) to depend on modules that are not being actively developed keeping pace with how SEO works today. So that's pretty much it. SEO NEO will be free. An Ultra/Pro version will follow and include genuinely useful additions for industry professionals. I'll have more soon, but if you have any SEO requests, my DMs are open. Cheers Peter
  17. --- Module Directory: https://modules.processwire.com/modules/privacy-wire/ Github: https://github.com/blaueQuelle/privacywire/ Packagist:https://packagist.org/packages/blauequelle/privacywire Module Class Name: PrivacyWire Changelog: https://github.com/blaueQuelle/privacywire/blob/master/Changelog.md --- This module is (yet another) way for implementing a cookie management solution. Of course there are several other possibilities: - https://processwire.com/talk/topic/22920-klaro-cookie-consent-manager/ - https://github.com/webmanufaktur/CookieManagementBanner - https://github.com/johannesdachsel/cookiemonster - https://www.oiljs.org/ - ... and so on ... In this module you can configure which kind of cookie categories you want to manage: You can also enable the support for respecting the Do-Not-Track (DNT) header to don't annoy users, who already decided for all their browsing experience. Currently there are four possible cookie groups: - Necessary (always enabled) - Functional - Statistics - Marketing - External Media All groups can be renamed, so feel free to use other cookie group names. I just haven't found a way to implement a "repeater like" field as configurable module field ... When you want to load specific scripts ( like Google Analytics, Google Maps, ...) only after the user's content to this specific category of cookies, just use the following script syntax: <script type="text/plain" data-type="text/javascript" data-category="statistics" data-src="/path/to/your/statistic/script.js"></script> <script type="text/plain" data-type="text/javascript" data-category="marketing" data-src="/path/to/your/mareketing/script.js"></script> <script type="text/plain" data-type="text/javascript" data-category="external_media" data-src="/path/to/your/external-media/script.js"></script> <script type="text/plain" data-type="text/javascript" data-category="marketing">console.log("Inline scripts are also working!");</script> The data-attributes (data-type and data-category) are required to get recognized by PrivacyWire. the data-attributes are giving hints, how the script shall be loaded, if the data-category is within the cookie consents of the user. These scripts are loaded asynchronously after the user made the decision. If you want to give the users the possibility to change their consent, you can use the following Textformatter: [[privacywire-choose-cookies]] It's planned to add also other Textformatters to opt-out of specific cookie groups or delete the whole consent cookie. You can also add a custom link to output the banner again with a link / button with following class: <a href="#" class="privacywire-show-options">Show Cookie Options</a> <button class="privacywire-show-options">Show Cookie Options</button> I would love to hear your feedback ? CHANGELOG You can find the always up-to-date changelog file here.
  18. Hi, everyone! We recently built a small add-on module for our StripePaymentLinks setup and thought it might be useful to share here. We’ve been working with StripePaymentLinks quite a lot lately, and one thing the clients always wanted was a simple way to get purchases synced into Mailchimp without relying on external paid add-ons. So we built a small ProcessWire module to handle exactly that. The idea is simple: every time a customer makes a purchase via StripePaymentLinks, their details (name, email) plus the purchased products (as tags) get synced directly into Mailchimp. That means you can instantly segment, automate, and follow up with buyers without any manual exports. We built this because we didn’t want to rely on a separate paid Stripe → Mailchimp connector. With this add-on, it’s all handled natively inside ProcessWire — lightweight, minimal, and no extra subscription fees. What it does right now: Hooks into the creation of purchase repeater items (repeater_spl_purchases) Pulls customer name + email from the User created by StripePaymentLinks Extracts product names either from the expanded Stripe session line_items or as fallback from the purchase_lines field Pushes everything to Mailchimp, creating the subscriber if you allow it in the config Assigns the product titles as Mailchimp tags Config is super simple: just drop in your Mailchimp API key, Audience ID, and decide if you want to auto-create subscribers or only update existing ones. We’re keeping this intentionally minimal — one module, no extra steps, no fuss. Install, configure, and you’re done. We’ve been running it in production for some clients and it’s working reliably. If you’re already using StripePaymentLinks, this could save you the cost of external integrations while keeping everything in one place. Get it here: ProcessWire: https://processwire.com/modules/stripe-pl-mailchimp-sync/ Github: https://github.com/frameless-at/StripePlMailchimpSync Happy to hear your feedback or ideas for tweaks. Cheers, Mike from frameless Media
  19. Hey everyone, we just released a small companion module for StripePaymentLinks: 👉 GitHub: https://github.com/frameless-at/StripePlCustomerPortal PW Repo: https://processwire.com/modules/stripe-pl-customer-portal What it does The module auto-creates a ready-to-use page at /account/ where logged-in customers can: view all their purchases (table or grid view) access their purchased products / membership pages update profile data (name + password) open Stripe’s Customer Portal to download invoices or manage subscriptions No custom template coding required — the module installs a template + page, and you can still override the markup if you want. ⸻ Why we built it StripePaymentLinks already handles the checkout & user/purchase creation. This module completes the loop and gives customers a proper account area. 💡 Bonus benefit (Marketing): The grid view not only shows purchased products — it also shows available-but-not-yet-purchased products in greyscale. This turns the account page into a soft upsell area without being salesy. ⸻ Requirements ProcessWire 3.0.210+ StripePaymentLinks module installed & working Stripe Billing Portal must be enabled (Stripe → Settings → Billing → Customer Portal) ⸻ Status 🚧 BETA — already used on live sites, but we’d love developer feedback. If you try it out, please tell us what works and what’s still missing. Issues / PRs welcome. ⸻ Cheers & happy coding, frameless Media
  20. Hey everyone! After the StripePaymentLinks module has been running smoothly, a few customers with multiple Stripe accounts asked for better analytics capabilities. The Stripe dashboard is okay, but when you have multiple accounts and need specific analysis, it quickly becomes tedious. StripePlAdmin is an admin interface that displays the data stored by StripePaymentLinks in three perspectives: Purchases: All transactions with customer details, subscription status, renewals Products: Aggregated product performance (revenue, purchases, quantities) Customers: Customer lifetime value, purchase behavior Features: Configurable columns per tab Dynamic filters (Boolean search, date ranges, number ranges) Clickable product/customer names open detail modals CSV export with active filters Summary totals at table footer You can show/hide columns and filters in the module settings as needed. Everything is very flexible. Available on GitHub and in the Modules directory. Feedback welcome! 🚀 Cheers, Mike
  21. Hi everyone, This module completely replaces the default ProcessWire image sizing engine with the powerful Intervention Image v3 library. The goal was to modernize how we handle images in ProcessWire, bringing in features like AVIF support, superior resizing quality, and strict aspect-ratio handling, while keeping the API compatible with what you already know. 🚀 What does it do? Replacement: It hooks into Pageimage. You can keep using $image->width(300), $image->size(800, 600), or $image->crop(...) just like you always have. Modern Formats: Automatically handles WebP and AVIF generation. Smart Responsive Images: It introduces a configuration-based approach where you define Breakpoints, Grid Columns, and Resizing Factors. The module uses these settings to automatically calculate and generate the perfect srcset for your layouts. ✨ New Methods: render() and attrs() While standard methods work as expected, I’ve added/updated methods to handle modern HTML output: 1. $image->render(string $preset, array $options) This outputs the complete HTML tag. It automatically handles: The <img> tag with srcset and sizes. The <picture> tag with <source> elements if you have enabled extra formats (like AVIF/WebP) in the settings. Lazy Loading & LQIP: It automatically generates a Low Quality Image Placeholder (pixelated/blur effect) and applies a base64 background to the image tag for a smooth loading experience. // Example: Render a 'landscape' preset defined in module settings echo $page->image->render('landscape', ['class' => 'my-image']); 2. $image->attrs(string $preset, array $options) Perfect for developers who use template engines like Twig or Latte, or prefer full control over their HTML. This returns an array of attributes instead of an HTML string. $data = $page->image->attrs('landscape'); // Returns array like: // [ // 'src' => '...', // 'width' => 1200, // 'height' => 675, // 'srcset' => '...', // 'sources' => [ ... ], // Array for picture tag sources // 'style' => 'background-image: url(data:image...);', // LQIP Base64 // 'class' => 'iv-lazy ...' // ] ⚙️ Configuration Strategy Instead of hardcoding sizes in your templates, you configure your design tokens in the module settings: Breakpoints (e.g., 1200px) Aspect Ratios (e.g., 16:9) Grid Columns (e.g., 1-1, 1-2, 1-3) Factors (e.g., 0.5, 1, 1.5, 2 for Retina support) The module calculates the necessary image dimensions based on these combinations. If you request a specific aspect ratio, it ensures strict adherence to it, preventing 1px rounding errors. Download / GitHub: GitHub Repo I’d love to hear your feedback and suggestions!
  22. Hi all — we're putting this one up as a public beta and looking for feedback before we tag a stable release. How it started. Over the past months we've been moving an old blog into a fresh PW site using our own SiteSync module and a Claude Code agent doing most of the migration grunt work. At some point the blog owner mentioned, in that very offhand way clients do, "hey, an image search would be nice." It was Saturday afternoon, so we let the agent build a prototype, pushed it through SiteSync, tested it on the phone an hour later. Worked great. Search results were… not great. But the search wasn't the problem – the underlying data was. Thousands of imported images, almost no descriptions, no tags, no nothing. So we needed a way to retroactively caption and tag a few thousand images without clicking through hundreds of page edits one by one. Since PW (rightly) attaches images to the pages they belong to, we needed a tool that reaches across the whole install at once and – crucially – can edit metadata in bulk. Why not the existing modules? We looked at the two obvious candidates: Media Manager by @kongondo – great if you're starting fresh and want a central media hub. But it's its own storage layer: you upload INTO Media Manager, editors pick FROM Media Manager. Images already sitting on per-page image fields stay invisible to it. Also commercial. MediaLibrary by @BitPoet – adds a MediaLibrary template with its own MediaImages / MediaFiles fields plus a CKEditor picker. Same pattern: a separate page hierarchy you migrate media into. Both are well-designed for "we want a central media model from day one." Neither helps you when the media is already scattered across lead_image, body_images, gallery, images_in_some_repeater etc. Migrating that into a different storage layer would have broken the original page model the blog depends on. So we built Image Library: a Process module that does nothing to your data – it just surfaces a cross-site table view of everything that's already there, with serious bulk editing on top. The bulk-edit part – the reason this module exists. Selection as a paintbrush. You tick N rows across any pages, templates and image fields. Then you edit a cell on ANY of those rows — the popup gains an Add / Replace mode picker (tags additionally offer Remove) and the value gets broadcast to the entire selection in one server round. Same row applies to description, tags, every custom subfield, AND the filename (with placeholders: (n), (n2)..(n5) padded counters, (N) total, (t) page title, (d) date, (p) page name, (f) field name → e.g. rename 200 selected files to event-2025-(n3).jpg). Same row applies to delete (one trash click, whole selection gone behind one confirm dialog with a where-used preflight – see below). Edits that push a row OUT of the active filter ("missing tags" → tag assigned → row no longer matches) fade out and drop from the table; counters auto-decrement. Other highlights: One sortable, paginated, bookmarkable table across every FieldtypeImage field on every page on every template (with config-side blacklists). Inline edit per cell – multilang-aware: language tabs in the popup, all languages committed in one save. Typed widgets per custom subfield: checkbox, date, integer, options (single + multi), and FieldtypePage rendered through PW's actually configured Inputfield (PageAutocomplete / PageListSelect / ASMSelect / whatever the field uses) — no re-implementation. Replace image in place (drag-drop or upload icon) – basename stays, variations regen. Renaming an image in the library instantly rewrites every CKEditor/TinyMCE embed of that file across the site — original and all variations, in every language — so links never break, and a summary dialog shows which pages were updated. Delete with where-used preflight: dialog scans every Textarea via $pages->findIDs("field%='/pid/stem.', include=all") and lists the pages where the image is still embedded in rich text – CKEditor + TinyMCE both, multilang-aware, with direct edit links so you can fix embeds before deleting. JSON / CSV export + import for offline metadata work – hand a CSV to a copywriter or feed it to your agent, get it back, import it. View prefs (columns, page size, bookmarks) live in $user->meta, cross-device. Status. v0.54.x – public beta. Module + docs (EN + DE concept) at GitHub or the Modules Directory Feedback welcome – especially edge cases we haven't seen yet (weird Fieldtype combos in custom-field templates, ProFields, Repeaters / RepeaterMatrix nesting). And if you've got a use case the current feature set doesn't cover, let us know. Cheers, Mike
  23. This module facilitates quick batch creation (titles only or CSV import for other fields), editing, sorting, deletion, and CSV export of all children under a given page. You can even provide an alternate parent page which allows for editing of an external page tree. http://modules.processwire.com/modules/batch-child-editor/ https://github.com/adrianbj/BatchChildEditor The interface can be added to the Children Tab, or in a new dedicated tab, or placed inline with other fields in the Content tab. Various modes allow you to: Lister - Embeds a customized Lister interface. Installation of ListerPro will allow inline ajax editing of displayed fields. Edit - This allows you to rename existing child pages and add new child pages. It is non-destructive and so could be used on child pages that have their own children or other content fields (not just title). It includes the ability to quickly sort and delete pages and change page templates. Also allows full editing of each page via a modal dialog by clicking on the page name link. This is my preferred default setup - see how it replaces the default Children/Subpages with an easily addable/editable/sortable/renamable/deletable list. Note that the edit links open each child page in a modal for quick editing of all fields. Add - adds newly entered page titles as child pages to the list of existing siblings. You could create a list of pages in Word or whatever and just paste them in here and viola! This screenshot shows the editor in its own tab (name is configurable) and shows some of the CSV creation options. Update and Replace modes look fairly similar but show existing page titles. Update - Updates the titles (and any other fields if you enter CSV data) for the existing pages and adds any additionally entered pages. Replace - Works similarly to Add, but replaces all the existing children. There are checks that prevent this method working if there are any child pages with their own children or other content fields that are not empty. This check can be disabled in the module config settings, but please be very careful with this. Export to CSV - Generates a CSV file containing the fields for all child pages. Fields to be exported can to fixed or customizable by the user. Also includes an API export method. Populating fields on new pages In Add, Update, and Replace modes you can enter CSV formatted rows to populate all text/numeric fields, making for an extremely quick way of creating new pages and populating their content fields. Predefined Field Pairings Like the field connections setup from Ryan's CSV Importer, but defined ahead of time so the dev controls what columns from the CSV pair with which PW fields. This is especially powerful in Update mode giving editors the ability to periodically import a CSV file to update only certain fields on a entire set of child pages. These pairings also allow for importing fieldtypes with subfields - verified to work for Profields Textareas and MapMarker fields, but I think should work for most others as well - let me know if you find any that don't work. Access permission This module requires a new permission: "batch-child-editor". This permission is created automatically on install and is added to the superuser role, but it is up to the developer to add the permission to other roles as required. Config Settings This module is HIGHLY configurable down to setting up custom descriptions and notes for your editors. You define one config globally for the site and then optionally you can define completely custom configurations for each page tree parent on your site. There are too many settings to bother showing here - you really just need to look through all the options and play around with them!
  24. This module allows you to automatically rename file (including image) uploads according to a configurable format This module lets you define as many rules as you need to determine how uploaded files will be named and you can have different rules for different pages, templates, fields, and file extensions, or one rule for all uploads. Renaming works for files uploaded via the admin interface and also via the API, including images added from remote URLs. Github: https://github.com/adrianbj/CustomUploadNames Modules Directory: http://modules.processwire.com/modules/process-custom-upload-names/ Renaming Rules The module config allows you to set an unlimited number of Rename Rules. You can define rules to specific fields, templates, pages, and file extensions. If a rule option is left blank, the rule with be applied to all fields/templates/pages/extensions. Leave Filename Format blank to prevent renaming for a specific field/template/page combo, overriding a more general rule. Rules are processed in order, so put more specific rules before more general ones. You can drag to change the order of rules as needed. The following variables can be used in the filename format: $page, $template, $field, and $file. For some of these (eg. $field->description), if they haven't been filled out and saved prior to uploading the image, renaming won't occur on upload, but will happen on page save (could be an issue if image has already been inserted into RTE/HTML field before page save). Some examples: $page->title mysite-{$template->name}-images $field->label $file->description {$page->name}-{$file->filesize}-kb prefix-[Y-m-d_H-i-s]-suffix (anything inside square brackets is is considered to be a PHP date format for the current date/time) randstring[n] (where n is the number of characters you want in the string) ### (custom number mask, eg. 001 if more than one image with same name on a page. This is an enhanced version of the automatic addition of numbers if required) If 'Rename on Save' is checked files will be renamed again each time a page is saved (admin or front-end via API). WARNING: this setting will break any direct links to the old filename, which is particularly relevant for images inserted into RTE/HTML fields. The Filename Format can be defined using plain text and PW $page variable, for example: mysite-{$page->path} You can preserve the uploaded filename for certain rules. This will allow you to set a general renaming rule for your entire site, but then add a rule for a specific page/template/field that does not rename the uploaded file. Just simply build the rule, but leave the Filename Format field empty. You can specify an optional character limit (to nearest whole word) for the length of the filename - useful if you are using $page->path, $path->name etc and have very long page names - eg. news articles, publication titles etc. NOTE - if you are using ProcessWire's webp features, be sure to use the useSrcExt because if you have jpg and png files on the same page and your rename rules result in the same name, you need to maintain the src extension so they are kept as separate files. $config->webpOptions = array( 'useSrcExt' => false, // Use source file extension in webp filename? (file.jpg.webp rather than file.webp) ); Acknowledgments The module config settings make use of code from Pete's EmailToPage module and the renaming function is based on this code from Ryan: http://processwire.com/talk/topic/3299-ability-to-define-convention-for-image-and-file-upload-names/?p=32623 (also see this post for his thoughts on file renaming and why it is the lazy way out - worth a read before deciding to use this module). NOTE: This should not be needed on most sites, but I work with lots of sites that host PDFs and photos/vectors that are available for download and I have always renamed the files on upload because clients will often upload files with horrible meaningless filenames like: Final ReportV6 web version for John Feb 23.PDF
  25. ProcessWire Dashboard Download You can find the latest release on Github. Documentation Check out the documentation to get started. This is where you'll find information about included panel types and configuration options. Custom Panels The goal was to make it simple to create custom panels. The easiest way to do that is to use the panel type template and have it render a file in your templates folder. This might be enough for 80% of all use cases. For anything more complex (FormBuilder submissions? Comments? Live chat?), you can add new panel types by creating modules that extend the DashboardPanel base class. Check out the documentation on custom panels or take a look at the HelloWorld panel to get started. I'm happy to merge any user-created modules into the main repo if they might be useful to more than a few people. Roadmap Panel types Google Analytics Draft At a glance / Page counter 404s Layout options Render multiple tabs per panel Chart panel load chart data from JS file (currently passed as PHP array)
×
×
  • Create New...