<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Nathan Speich: Building VolunteerPress]]></title><description><![CDATA[A weekly post on building a free volunteer management plugin for WordPress, in public.]]></description><link>https://blog.nathanspeich.com/s/building-volunteerpress</link><image><url>https://substackcdn.com/image/fetch/$s_!S7-e!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85926d67-d366-4153-bbad-c8ab4385d3cf_1800x1800.jpeg</url><title>Nathan Speich: Building VolunteerPress</title><link>https://blog.nathanspeich.com/s/building-volunteerpress</link></image><generator>Substack</generator><lastBuildDate>Fri, 11 Sep 2026 18:23:06 GMT</lastBuildDate><atom:link href="https://blog.nathanspeich.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Nathan Speich]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[nspeich@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[nspeich@substack.com]]></itunes:email><itunes:name><![CDATA[Nathan Speich]]></itunes:name></itunes:owner><itunes:author><![CDATA[Nathan Speich]]></itunes:author><googleplay:owner><![CDATA[nspeich@substack.com]]></googleplay:owner><googleplay:email><![CDATA[nspeich@substack.com]]></googleplay:email><googleplay:author><![CDATA[Nathan Speich]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The solo phase is over.]]></title><description><![CDATA[What it took to onboard the first contributors.]]></description><link>https://blog.nathanspeich.com/p/the-solo-phase-is-over</link><guid isPermaLink="false">https://blog.nathanspeich.com/p/the-solo-phase-is-over</guid><dc:creator><![CDATA[Nathan Speich]]></dc:creator><pubDate>Fri, 11 Sep 2026 15:43:06 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e30bbac3-3057-4a72-a13f-1c98d81a785c_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>On Saturday, September 5, VolunteerPress stopped being a one-developer project. That was the day of the first contributor onboarding session, held at <a href="https://www.improving.com/locations/columbus/">Improving</a> in Columbus during the <a href="https://christians-in-tech.org/">Christians in Tech Columbus</a> meetup. The first contributors got their laptops out and started setting up their development environments. The session itself is easy to describe. What&#8217;s worth writing about is the set of decisions that made it possible, and what watching contributors use them changed.</p><p>VolunteerPress is a WordPress plugin, so to work on it you need WordPress running on your own machine, which means PHP and a MySQL database. To check the code the way the project checks it, you also need Composer and Node. That&#8217;s five things that have to exist and agree with each other before you can change a single line of code, on whatever laptop you walked in with. The goal was concrete: someone should go from nothing installed to passing the same automated checks the project runs before every change, in one sitting. Every decision below came from that.</p><p>That goal decided the foundation. I chose LocalWP, a free desktop app that runs WordPress sites on your computer and ships its own PHP and MySQL. Docker is the more standard answer, and it&#8217;s what the WordPress core team uses for its own contributors. LocalWP won for three reasons. Onboarding is faster, because PHP, MySQL, and WordPress arrive together instead of one install at a time. The environment is standardized, because every contributor runs the PHP and MySQL that LocalWP ships, whatever their operating system. And it has a site shell: one click opens a terminal with that site&#8217;s PHP, database, and WordPress command line already wired up, so everyone starts from an identical place on Windows, macOS, or Linux. It&#8217;s also a tool WordPress developers already know from client work, and it works well for contributors at every skill level.</p><p>The trade-off is that contributors depend on a desktop app instead of assembling standard tools themselves, and if LocalWP changes something, our setup guide changes with it. For this project, that&#8217;s worth it.</p><p>That choice shaped the setup guide. It has three sections, one per operating system. Windows, macOS, and Linux each get their own path to installing LocalWP, Composer, and Node, and those three installs are the last point where the operating system matters. On Windows, for example, Composer needs to know where PHP lives, so rather than have people install a second copy, the guide points it at the one LocalWP already downloaded. From the moment you open the site shell, every command in the guide is identical for everyone. I wanted a contributor on Windows and a contributor on a Mac sitting next to each other to be able to look at each other&#8217;s screens and see the same thing.</p><p>Then there was deciding what &#8220;done&#8221; means for setup. Loading the site in a browser isn&#8217;t it. Passing the checks is. Every change to VolunteerPress, including a one-line fix to a documentation file, has to clear four of them: the PHP coding standards check, the JavaScript lint, the JavaScript unit tests, and the PHP test suite. Right now that&#8217;s 620 PHP tests with 3,720 assertions, and 21 JavaScript tests. The PHP test suite needs a live database and a setup the project only supports on Linux, so the work is split. Everyone runs the first three checks on their own machine, and GitHub runs all four automatically on every proposed change, whatever machine it came from. A contributor on Windows or a Mac never has to get the PHP test suite working locally.</p><p>Running checks for a typo fix sounds excessive, and I understand why. The reason to do it anyway is that the first time a contributor runs those commands, they&#8217;re not really testing the code. They&#8217;re testing their environment. If the checks pass, you&#8217;re set up, and that&#8217;s the point where the setup guide hands you off to picking up an issue.</p><p>The other decisions were about access and process. Contributors now join a Contributors team in the GitHub organization with triage permission on both repositories, the plugin and the <a href="https://volunteerpress.org/">volunteerpress.org</a> site. Every change starts as a filed issue, so there&#8217;s a record of what&#8217;s being worked on and why before any code moves. The one exception is an emergency fix, a security issue or a live-site outage, which can go out immediately as long as the issue is filed the same day. The record stays complete either way.</p><p>I also rewrote the issues labeled good first issue. A title and a sentence isn&#8217;t enough for a first issue. Each one now names the files involved and says what &#8220;done&#8221; looks like, so a new contributor can pick one up and know when to stop.</p><p>One more rule is about how the code gets written. Last week I said Claude Code wrote the code for version one while I owned the architecture, the requirements, and the testing. That&#8217;s still how it works, and contributors are welcome to work the same way. The rules that matter now live in the contributing guide and a conventions file, where both a person and an AI coding tool can read them: the four checks, the issues-first workflow, and review before anything merges. There&#8217;s a small file at the root of the repository that points any of those tools at both documents, whichever one a contributor prefers. An AI-assisted contribution goes through the same four checks and the same review as any other, and the contributor owns the result.</p><p>Very little of the work to open the project up was code. At launch, the plugin already had its tests, its coding standards, and a clean architecture. What it was missing was everything a second developer needs before touching any of that: a way to get a working environment, a definition of when setup is finished, a definition of when an issue is finished, and the project&#8217;s rules written down somewhere other than my head. Opening VolunteerPress to contributors meant building those things.</p><p>The setup guide that went into that session was a first version, not a final one. Every question a contributor asked that afternoon pointed at an assumption the guide was making without saying so. The steps were all there. What they needed was the clarity that comes from people willing to sit down, try it, and say where it stopped making sense. Those questions produced the version in the repository now, and that&#8217;s how every part of VolunteerPress moves: it ships, people use it, and it gets better. That&#8217;s what building in the open, with other people, gives you.</p><p>So here&#8217;s the change since last week. VolunteerPress is a team now, and it meets in person. For now, onboarding happens at <a href="https://christians-in-tech.org/">Christians in Tech Columbus</a> meetups. If you&#8217;re in Columbus or anywhere nearby and you&#8217;d like to build something that nonprofits will actually use, come to one, bring a laptop, and tell me you want in. You don&#8217;t need to be a WordPress developer, and you don&#8217;t need to be a regular. Where onboarding happens will change as the group grows beyond the meetup. Online sessions for people who can&#8217;t make it in person are part of the plan, with no date yet. Any changes will be posted at <a href="https://volunteerpress.org/contribute">volunteerpress.org/contribute</a>. If you&#8217;d rather ask a question first, write to <a href="mailto:hello@volunteerpress.org">hello@volunteerpress.org</a>.</p>]]></content:encoded></item><item><title><![CDATA[Finding volunteers was easy. Managing signups wasn't.]]></title><description><![CDATA[Why we built VolunteerPress, free volunteer management for WordPress, and how anyone can help build what's next.]]></description><link>https://blog.nathanspeich.com/p/why-we-built-volunteerpress</link><guid isPermaLink="false">https://blog.nathanspeich.com/p/why-we-built-volunteerpress</guid><dc:creator><![CDATA[Nathan Speich]]></dc:creator><pubDate>Thu, 03 Sep 2026 12:04:30 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8d29b58d-66f9-4275-96bf-39809ca4b1e7_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Small nonprofits in Columbus, Ohio, the kind that feed and house people, run entirely on volunteers. Through Christians in Tech Columbus, a meetup I co-founded and organize, I&#8217;ve sat with a handful of them, and every one described the same thing. Not one of them had trouble finding volunteers. Interest was never the problem. What they lacked was a way to manage the volunteers they had: to cap a shift, keep track of who was coming, and communicate with everyone without doing all of it by hand.</p><p>Here&#8217;s what that looked like. Volunteers found the organization&#8217;s website and filled out a contact form. A staff member read each one and replied by hand. There was no way to cap how many people signed up for a day, so too many showed up or too few. Then every name got typed into a database on a separate platform the organization was paying for. None of it was broken. It was just human hours going to work that software should have been doing, and those hours came straight out of the mission.</p><p>A few of us from the meetup started working on it with them. We mapped what they actually needed, tried what already existed, and weighed what it would take to build something new. The free WordPress plugins were too basic or no longer supported. The good tools cost $50 to $300 a month, which is hard for a small nonprofit to justify when that money could go to the people it serves. And the all-in-one nonprofit suites a few of them already paid for do include volunteer scheduling, but every volunteer has to download an app and create an account to use it. The nonprofits wouldn&#8217;t ask that of someone who just wants to show up and help. What they wanted was simple to say and hard to find: signups on the site they already have, with limits, no new accounts, and no person in the middle.</p><p>The &#8220;site they already have&#8221; part decided the platform. Nearly six in ten nonprofits worldwide run their websites on WordPress, according to Nonprofit Tech for Good&#8217;s <a href="https://www.nptechforgood.com/101-best-practices/website-statistics-for-nonprofits/">Global NGO Technology Report</a>. Building for WordPress meant the fix could land inside something they already own. It also meant the work wouldn&#8217;t stop at Columbus. The same manual process is happening at small nonprofits everywhere, and most of them are on WordPress too. Solve it once as a plugin, and every one of them can install it.</p><p>That&#8217;s where VolunteerPress came from. I took version one on myself to get something real in front of them. Claude Code wrote the code, and I owned the architecture, the requirements, and the testing. Every change runs through automated tests and WordPress coding-standard checks (PHPUnit, phpcs, and JS lint) before it merges. Right now that&#8217;s 620 PHP tests and 21 JS tests. I&#8217;ll write a full post on how that workflow really looks. &#8220;AI-assisted development&#8221; sounds hands-off. It isn&#8217;t.</p><p>The most important choice in version one isn&#8217;t a feature at all. VolunteerPress doesn&#8217;t bring its own look. The signup form, shift list, and calendar inherit whatever the site&#8217;s theme already uses, so there&#8217;s nothing to style, nothing to configure, and no designer to hire. A volunteer signing up sees the same site they already trust, not a form that looks bolted on. That&#8217;s the reason it works on themes none of us have seen.</p><p>Version 1.0 went live on August 22, the same morning I gave the first talk on it at the meetup and ran a live demo that afternoon. 1.0.1 followed a day later with fixes from that first round of feedback, and that&#8217;s how it&#8217;ll keep going: the roadmap is driven by what the nonprofits we&#8217;re working with ask for. Volunteer hours tracking, which they need for grant reporting, is one of the first things coming. It&#8217;s free, open source (GPL), and self-hosted: you download it from <a href="https://volunteerpress.org">volunteerpress.org</a>, it updates itself from there like any other plugin, and the source ships in the zip.</p><p>The solo phase is over. VolunteerPress is an open source project with an in-person on-ramp: you come to an onboarding session, get set up on the codebase, pick up an issue, and own it through review. Anyone is welcome, and you don&#8217;t have to be part of the meetup to come. The first session is Saturday, September 5, at Improving in Columbus, running alongside the Christians in Tech Columbus meetup. Future sessions will be listed at <a href="https://volunteerpress.org/contribute">volunteerpress.org/contribute</a>.</p><p>I&#8217;ll be writing here every Thursday. For now that means building VolunteerPress: what shipped, what broke, and what we learned along the way.</p><p>If you run a nonprofit&#8217;s website on WordPress, download it and tell us what happens. Write to <a href="mailto:hello@volunteerpress.org">hello@volunteerpress.org</a>. Especially if you&#8217;re the one replying to contact form submissions by hand right now.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.nathanspeich.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item></channel></rss>