PaintOps

Description

PaintOps turns your WordPress site into the back office for your painting business. Build professional quotes, send them to customers who can view, e-sign, and pay a deposit online, schedule crews on a calendar, track every job from lead to invoice, and, on Pro, see your real profit per job, per crew, and per worker.

It was built by a painter, for painters. The quote builder understands painting scope: interior/exterior components, standard inclusions and exclusions, and the disclaimer language that keeps you out of disputes. Your data lives in your own WordPress database, not locked inside someone else’s SaaS.

Quote to invoice, start to finish

  • Quotes, estimates & bids: a scope-aware builder with reusable inclusions/exclusions, itemized or lump-sum pricing, printable output, and email delivery.
  • A professional customer page: your customer opens a clean, branded page (your logo, your terms & conditions) and accepts by typing their name, an e-signature-grade record with timestamp. They can also decline with a reason, or ask a question, and you’re notified either way.
  • Acceptance converts the quote to a job automatically, whether they paid a deposit online or you shook hands, and a “Mark as Won” button covers the phone call.
  • Invoices: numbered invoices for the balance (full or partial), emailed or shared by link, payable online (Pro + Stripe) or marked paid for check/cash, with the payment logged so balances always agree.
  • Receivables at a glance: unpaid invoices surface on your dashboard with amounts and age.

Running the work

  • Scheduling calendar with crew filtering, worker badges, time-off, and a subscribe link for Google/Apple/Outlook. Add your own recurring holiday labels.
  • Crews: group your painters into named, colored crews; staff a job with one tap and filter the calendar and reports by crew.
  • Job board / pipeline: Quote Active Completed, plus a lost-leads drawer with the customer’s decline reason so you can revive the ones worth re-working.
  • A real app for your painters: install-to-home-screen (PWA), a “My Jobs” home, one-tap directions (Google/Apple/Waze), per-job check-in/out that works offline and syncs, photo/receipt/note logging, a “My Hours” view of their own time and pay, and a “Mark Job Complete” button that notifies the office. Workers see only what their permissions allow, never your numbers.
  • Customers: a directory with contact details, lifetime value, job history, and multiple service addresses per customer, built for landlords, realtors, property managers, and GCs whose one account means a dozen properties.
  • Before/After photos with camera alignment overlay and a compare slider.
  • Trade calculators, paint-color tracking, and resource links.
  • A choice of visual themes (light, dark, industrial, and more) with a modern app-style navigation bar on desktop and phone.

What Pro adds

  • Job financials & profitability: costs, materials, labor hours; gross, expenses, profit, and margin per job; a Profits dashboard with profit-by-classification, profit-per-hour rankings, and profit by crew and by worker (allocated by logged hours).
  • Expenses & receipts against any job, plus business-level and vehicle expense tracking for tax time.
  • Online payments: deposits on quote acceptance and invoice balances through Stripe Checkout, recorded automatically.
  • AI tools (bring your own OpenAI key): estimate dimensions, gallons, and a Description of Work from a photo; scan receipts to auto-fill expenses; get feedback on or a rewrite of your quote wording.

Pro is a paid upgrade handled through Freemius. The free plugin is fully functional on its own; Pro is optional.

External services

This plugin can connect to the following third-party services. Some are optional and only run when you enable and configure the corresponding feature.

OpenAI (Pro AI features, optional). When you use an AI feature (Photo Estimate, Receipt Scan, Description-of-Work Feedback or Rewrite), the plugin sends the relevant input, the photo you choose to upload and/or the quote text you are working on, to the OpenAI API using your own OpenAI API key, and receives the generated result. No data is sent unless you click one of these buttons. PaintOps does not store the photo. Requests go to https://api.openai.com. See OpenAI’s Terms (https://openai.com/policies/terms-of-use) and Privacy Policy (https://openai.com/policies/privacy-policy).

Stripe (Pro online payments, optional). If you enable card payments and a customer pays online, the plugin creates a Stripe Checkout session and verifies Stripe’s webhook using your own Stripe keys. Order/amount details are exchanged with Stripe to process the payment. Requests go to https://api.stripe.com. See Stripe’s Services Agreement (https://stripe.com/legal/ssa) and Privacy Policy (https://stripe.com/privacy).

Google Maps Platform (optional). If you add a Google Maps API key, address fields use Google Places/Geocoding for autocomplete and validation, and job locations may be shown on an embedded map. The address text you type is sent to Google to return suggestions. Requests go to https://maps.googleapis.com and related Google Maps endpoints. See Google’s Terms (https://cloud.google.com/maps-platform/terms) and Privacy Policy (https://policies.google.com/privacy). (One-tap turn-by-turn Directions for your crew use keyless map links and need no API key.)

YouTube and Vimeo (Resources page video embeds, optional). The Resources page (staff-facing, inside your admin area) lets you save links to training videos, and seeds a starter list of publicly available painting tutorials on YouTube. When a staff member clicks a saved YouTube or Vimeo link’s play button, the video is embedded on the page via the provider’s standard embed player (www.youtube.com / player.vimeo.com), which loads content from that provider and is subject to its terms; no data is sent until the play button is clicked, and you can delete any or all saved links. See YouTube’s Terms (https://www.youtube.com/t/terms) and Google’s Privacy Policy (https://policies.google.com/privacy), and Vimeo’s Terms (https://vimeo.com/terms) and Privacy Policy (https://vimeo.com/privacy).

Freemius (licensing & updates). PaintOps uses the Freemius SDK to manage Pro licenses, deliver Pro updates, and (optionally) collect anonymous usage diagnostics you can opt out of. Site and license information is exchanged with Freemius. See Freemius’s Terms (https://freemius.com/terms/) and Privacy Policy (https://freemius.com/privacy/).

You control every one of these by whether you enter the corresponding API key and enable the feature. With no keys entered, PaintOps runs entirely on your own site.

Screenshots

Installation

  1. Install PaintOps from the Plugins screen (Plugins Add New search “PaintOps”), or upload the plugin ZIP under Plugins Add New Upload Plugin. Activate it.
  2. Create a WordPress Page and add the shortcode [paintops_app]. This one page is your whole PaintOps app; it routes internally.
  3. Go to PaintOps Settings and set your Company Profile (business name, logo, country, currency), and review the Setup Health panel.
  4. (Optional) Add team members under PaintOps Painters/Helpers, set their permissions, and group them into Crews.
  5. (Optional) Add your Quote Terms & Conditions under Business Settings so customers see and sign against them.
  6. (Optional, Pro) Under Settings AI Settings connect OpenAI, under Stripe Payments add your Stripe secret key AND webhook signing secret (both are required before online payment buttons appear), and add a Google Maps API key for address autocomplete.

FAQ

Do I need a paid account to use it?

No. The free plugin runs entirely on your own WordPress site and lets you quote, schedule, and manage unlimited jobs. Pro is an optional upgrade.

What happens to my data if I deactivate or delete the plugin?

Nothing is deleted. Your jobs, quotes, customers, payments, hours, and photos stay in your WordPress database, so nothing is lost if you deactivate temporarily or reinstall later. If you truly want the data gone, delete the plugin’s tables and its uploads from your database and media library.

Does it work without OpenAI, Stripe, or Google Maps?

Yes. Those are optional integrations. If you don’t enter their keys, the related features simply stay off and everything else works, including keyless turn-by-turn directions for your crew.

Can my customers really sign a quote online?

They accept by typing their full name, which is stored with a timestamp and IP address alongside your Terms & Conditions, a solid acceptance record. They can also decline with a reason, and change their minds later.

Who pays for the AI usage?

You do, through your own OpenAI account and key, typically a fraction of a cent to a few cents per action. PaintOps adds per-month usage caps you control so costs stay predictable.

Can my painters log in without seeing my numbers?

Yes. Painters/Helpers get a dedicated role with opt-in permissions and their own app view: My Jobs, My Hours (their own time and pay only), directions, check-in/out, photos and receipts. Financial figures are owner-level and hidden from workers unless you explicitly grant access.

Does it work in the field with bad reception?

The app installs to a phone’s home screen, and Time Clock check-in/out keeps working offline and syncs when a connection returns.

Where is my data stored?

In your own WordPress database. PaintOps doesn’t host your business data on an external server.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“PaintOps” is open source software. The following people have contributed to this plugin.

Contributors

Translate “PaintOps” into your language.

Interested in development?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Changelog

1.0.295

  • Fixed: some in-app cards (including the painter “My Jobs” home screen) could show overlapping text on certain sites, because an inline display style was being stripped by WordPress’s HTML sanitizer. The cards now render correctly.
  • Fixed: add-on and follow-up visit jobs now show their dollar value on the Job Board. Previously the Value column was blank when the amount came from the Financials page instead of a quote.
  • Fixed: opening a job that had no scheduled arrival time (or was not scheduled yet) could show a blank page. The job view now renders in every case.
  • Hardening: the Time Off page no longer errors if a stored date is malformed.

1.0.294

  • New: a per-user option on the Profits and Business pages to include jobs marked “exclude from reports” in the on-screen stats. It is saved per user and remembered.
  • Note: your Business Financial Report / accountant sheet never includes these excluded jobs, regardless of this setting; it only changes what you see on the dashboards.

1.0.293

  • New: the Row view now has a per-row Actions menu (Mark Completed, Back to Request, and the usual job actions), matching what the Board offers, styled to fit the row rather than as buttons.
  • Improved: link colors are now consistent across the app; job titles in the Row view use the same accent color as everywhere else.
  • Changed: removed the search box from the Jobs page, since the search now lives in the app-wide top bar.

1.0.292

  • New: the job search box now lives in the top bar next to + New, so you can search from anywhere in the app, not just the Jobs page.
  • Improved: the Schedule a Callback / Punch List Visit page now carries the same job section menu as the rest of a job’s pages, instead of a lone back link.
  • Improved: on the quote builder, the AI Photo Estimator and the AI feedback / rewrite / materials buttons are tucked into a single “AI Tools” drawer, keeping the Description of Work area clean.

1.0.291

  • New: the Jobs page search box is now a live search. Type three or more characters to see matching jobs as you type, and pick one to jump straight to it.
  • New: an “All Fields” search option that matches your term across customer name, email, address, phone, job title, and job number at once. Pressing Enter in the live search runs a full All-Fields search.

1.0.290

  • Fixed: on mobile, the menu (hamburger) button is now a crisp, high-contrast icon that no longer depends on a web font loading, so it’s always clearly visible.
  • Fixed: app icons could render blank on some screens (and inside the installed app), which made the app look half-styled; the icon font is now loaded on every app screen.

1.0.289

  • Added: a Search button at the top-right of the Jobs page that opens the full Completed & all-jobs search.
  • Fixed: on the Board view, the “Completed & all jobs” link is back, and the Board/Row toggle now matches the same clear accent-link style as the rest of the footer.
  • Fixed: on the Seaside theme, the Board/Row switch link was hard to read and vanished on hover; it now stays a legible accent color, hover included.

1.0.288

  • Improved: the job actions menu now appears on the Job View page too (with “View Job” marked as the current page), so it’s identical across every job section.
  • Changed: renamed the menu’s “Job” tile to “View Job”.
  • Fixed: on a job’s sub-pages, the More Actions menu now stays collapsed by default (its tile is highlighted when the current section lives inside it) instead of opening automatically.
  • Added: the Job Profit Report Summary now shows an “Admin only” note above the figures, making clear your painters can’t see profit numbers.

1.0.287

  • Improved: on the Profits page, This Year and Last Year now line their columns up exactly, so the two years are easy to scan and compare side by side.
  • Improved: the Job View action icons (Directions, Add Expense, Notes & Photos, More Actions) now match the crisp line-icons in the main menu.
  • Improved: every job section (Add Expense, Notes & Photos, Financials, Edit, and the quote view) now carries the same job actions menu with the current section highlighted, instead of a lone back link, so moving between a job’s pages is one consistent, permission-based menu.
  • Improved: when a quote’s More Actions has only one option (Replace Quote), it now shows as a plain action instead of a single-item dropdown.

1.0.286

  • Improved: the Profits page is redesigned to read at a glance. Each year now leads with a single Profit figure and lists the rest as light supporting stats instead of a row of boxed tiles, This Year and Last Year share the same layout for easy comparison, and the Profit-per-hour ranking cards use a compact stat line.
  • Improved: unified the link styling in the Jobs list footer so the “Completed & all jobs” link and the Board/Row view toggle match.

1.0.285

  • Improved: section headers (like the dashboard’s “Today” bar) are now a clean bold heading instead of a boxed, accented bar, so they guide the eye without over-drawing attention.

1.0.284

  • Improved: the sidebar layout now keeps content in a comfortable, compact column instead of stretching edge to edge, so pages read cleaner on wide screens. Wide tables still scroll on their own when needed.

1.0.283

  • Fixed: the dashboard “Unpaid Invoices” receivable now reflects payments you’ve recorded anywhere, not just the invoice’s own “Mark as Paid”. Recording a payment in a job’s Payments log now reduces (or clears) what that invoice shows as outstanding, so a partly paid invoice shows the real balance and a fully paid one drops off. When a payment covers the job in full, its invoice is also marked paid automatically.
  • Improved: the Jobs list rows now show small Crew, Date, and Value labels above those columns, so the numbers on the right aren’t ambiguous.

1.0.282

  • Improved: filing a receipt now highlights Expenses in the sidebar (both the File a Receipt page and a job’s Add Expense screen), so it’s clear where you are.
  • Changed: Outstanding Balances moved from the Profits page to the Business page, where the rest of your money and tax sections live.

1.0.281

  • Changed: the Sidebar layout is now on by default, so the app opens in the cleaner full-screen sidebar view with no site header. You can switch back to the classic top-bar layout any time at Settings > Appearance > Navigation > Layout.

1.0.280

  • New: a Business Notes page (Free and Pro) for reminders, vendor account numbers, insurance renewal dates, anything worth keeping. New note, edit, and delete, found under More (or the sidebar’s Tools group).
  • New: the “+ New” button is now a chooser, New Request or File a Receipt, so filing a receipt is no longer buried. File a Receipt opens one page where you pick “Not Tied to a Job” (business overhead, the default) or attach it to a job from a searchable list.
  • Improved: business and overhead receipts moved to their own Expenses page, so the Business page stays focused on tax buckets, reports, team, and backup. The Expenses page keeps the Scan-with-AI / Manually-Enter chooser and in-place editing.
  • New: an optional Sidebar layout (Settings > Appearance). Shows the app with a left sidebar menu and no site header or footer, with your business logo in the sidebar. Off by default; the classic top-bar layout is unchanged unless you turn it on.

1.0.279

  • Improved: the Business page Add Expense form now matches the clean job Add Expense screen. You choose “Scan Receipt with AI” or “Manually Enter” first, instead of every field showing at once.
  • Added: you can now edit a logged expense (date, vendor, category, amount, and notes) in place, both on a job’s expense list and on the Business page, so a mis-scanned category or a wrong amount is a quick fix instead of deleting and re-adding.
  • Fixed: the job Add Expense screen no longer says AI can’t read PDF receipts. It has read PDFs since 1.0.276.
  • Fixed: uploading a PDF receipt no longer triggers PHP notices while saving the file (the upload always worked; the notices were just noise).
  • Improved: scanning a receipt on the Business page now also fills the Notes field with a short summary of the items purchased (e.g. “2 gal SW Emerald, 3 rollers”), leaving anything you already typed untouched.
  • Improved: the Business page is reorganized. One tax-year switch at the top now drives the whole page (the year is no longer buried inside a section), and a summary row shows Income, Job Materials, Vehicle, and Total Deductions at a glance. Jobs set to exclude from financial reports are left out of the page’s totals, receipt search, and duplicate finder.
  • Fixed: scanning a receipt on the Business page now fills in the category from your own business categories, and recognizes an existing vendor even when the receipt shows a store number (for example “Sherwin-Williams #402”) instead of pushing you to create a duplicate.
  • Improved: the Business page Find Duplicates tool now checks job receipts and business/overhead expenses together, matched on the same date and amount, so a receipt entered on a job and again as overhead is flagged as appearing in both places.

1.0.276

  • Improved: AI receipt scanning (Pro) now reads PDF receipts as well as photos. Emailed receipts saved as PDFs can be scanned directly on job expenses, business expenses, and the vehicle log, with a page-length guardrail so only receipt-sized PDFs are sent for reading.

1.0.275

  • Fixed: many in-app links (Create Quote in More Actions, calendar month arrows, back links, save banners, and others) could land on the site’s blog page on sites using plain permalinks. Every link now carries the app page with it.
  • Fixed: the Jobs page rows squeezed the job title to almost nothing inside themes with a normal content column. Rows now adapt to the width of their own card.
  • Fixed: a false “You are offline” banner and an unstyled Install PaintOps button could appear at the bottom of some screens.
  • Fixed: new quotes printed the paint color confirmation paragraph twice in the Exclusions. The duplicate starter clause is removed and already-saved notes are cleaned up automatically on update.
  • Improved: if the quote email fails to send (common on hosting without a mail service), the screen now explains why and shows the customer’s accept link to copy and send yourself.
  • Improved: after saving a quote you now get Open, Email It to the Customer, and Back to the Job actions instead of a bare one-line notice.
  • Fixed: the customer accept page now always shows the accept-by date, even before Quote Terms are saved.
  • Changed: the Complete / Not Complete pill on the job view now submits a form instead of following a link, so browser prefetching can never flip a job’s status.
  • Fixed: on the free plan, the Collect link on finished unpaid jobs goes to the job’s Mark as Paid action instead of an upgrade screen. Pro still goes straight to the Payments log.
  • Fixed: quote emails and review request emails no longer show blank spots before the business profile is filled in. The signature and business name fall back to the site title.
  • Changed: the itemize section on the quote form starts collapsed.

1.0.274

  • The Complete / Not Complete toggle on the job view now redirects to a clean URL after saving, so browser refresh or Back can never flip it again, and the app tells page-caching plugins never to cache its screens for logged-in users (a cached copy could show a job’s old status after a change).
  • The Jobs page’s Collect link on unpaid finished jobs now opens the job’s Financials page instead of the job view.

1.0.273

  • The Jobs page has a new default view: clean rows grouped into Active Jobs, Quotes Out, and Wrapping Up, in the same order every day, with crew, dates, amounts, quote viewed/quiet states, and one-click follow-ups. The classic three-column board is still there via the Switch to Board view link at the bottom of the page.

1.0.272

  • A fresh coat for the whole app: modern type, softer corners, and cleaner card surfaces across every screen and every theme. The Seaside theme also gets a soft page background so cards stand out, and its secondary text regains a readable muted tone.

1.0.271

  • Pro: job receipt coversheets opened from a Business-page tax year now limit their expense lines and attached receipts to that year, so year-straddling jobs print a clean per-year filing bundle (undated entries stay included, and whole-job Profit Summary figures are labeled as such).

1.0.270

  • Quotes now carry a validity date (default 30 days, configurable under Business Settings, 0 disables). The valid-until date prints at the bottom of the quote, and once it passes, the customer accept page stops taking online acceptances and invites the customer to request updated pricing. Already-accepted quotes are never affected.

1.0.269

  • Pro: Google review requests. Set your Google review link and a default email under Settings, and the Jobs page suggests completed jobs whose customers haven’t been asked yet, with a preview-and-edit compose screen, one-click dismiss, and every send logged to the job’s communications.

1.0.268

  • Pro: after upgrading from the free version, the leftover deactivated free copy is now removed automatically (with a confirmation notice). No data is affected.

1.0.267

  • Jobs dashboard: quotes you know are dead can now be archived straight from Needs Your Attention; Archive marks the quote Not Won (same as the job board action, reversible there) and Not Won quotes no longer appear in the stale-quotes list.

1.0.266

  • Jobs dashboard: sending a follow-up email or tapping Text Follow-Up now clears the quote from Needs Your Attention (any logged communication inside the stale window counts as activity, and the quote resurfaces if the customer stays quiet past it). The dashboard Text Follow-Up tap is also logged to the job’s communications like everywhere else.
  • Pro: new one-time welcome screen shown after activation with what’s new and first setup steps.

1.0.265

  • Time Off: the Year/Month/Day row now carries its 3-column layout inline, so it renders identically on every site regardless of stylesheet load order (it previously collided with the 4-column address-row definition and could render 4-up on some themes).

1.0.264

  • Theme compatibility: the plugin’s own UI elements now pin box-sizing: border-box, so buttons and multi-column forms render as designed on themes that lack a global border-box reset. No visual change on themes that already have one.

1.0.263

  • Reverted the 1.0.261/1.0.262 app-wide button sizing changes; the compact height now applies only to the job board’s + New Request button.

1.0.262

  • App buttons: fixed the inflated button height on themes without a border-box reset (box-sizing now set explicitly) and tightened the desktop button profile to about 36px; touch devices keep the full 44px tap target.

1.0.261

  • Job board: the compact action buttons inside card drawers (Reopen as Job, stage moves) no longer inherit the app-wide 44px touch-target height on desktop; touch devices keep the full 44px tap target.

1.0.260

  • Security review round 3: pdf.js is now bundled with the plugin (assets/vendor/pdfjs) instead of loaded from cdnjs; the unused media.php core include was removed; nonce verification is now the first standalone statement in the reminder AJAX handler and explicit inside the calculator readers; remaining sanitize sites gained wp_unslash; token-authenticated public endpoints and read-only display filters are documented at each read site.

1.0.259

  • Code quality: the Estimates, Calendar, Time Off, and Business Checkup screen files are now wrapped in named render functions, making their variables explicitly function-scoped and clearing all 575 variable-prefix warnings from the wordpress.org hosted Plugin Check.
  • Code quality: documented ignores on the field-mapping loops whose keys come from fixed schema or whitelist lists.

1.0.258

  • Admin notices from the licensing SDK now use a plainer tone (“Success! Your plan was successfully upgraded.” instead of “Yee-haw!”).

1.0.257

  • Final Plugin Check cleanup: the five remaining tool warnings (array-form prepare arguments miscounted, and two documented meta-key lookups) now carry scoped annotations the checker honors. No functional changes.

1.0.256

  • The Calendar screen now prints its own “Calendar” heading. It was the one screen that relied on the theme’s page title, which PaintOps hides on app pages, so on some themes the calendar had no visible title.

1.0.255

  • Fix: on themes whose navigation menu or page list includes the PaintOps app page, the menu label wrongly showed the current app screen name (for example “Calendar”) instead of the page’s own name. The dynamic title now applies only to the page’s actual title areas.

1.0.254

  • Plugin Check zero-error pass: the plugin header’s “Requires at least” now matches the readme at 6.2 (this also clears every false %i placeholder error), all escaped output calls wp_kses() by its literal name so scanners recognize the escaping, the Business Checkup queries carry their fixed SQL conditions inline, the calendar’s crew filter is part of one static prepared query, and the remaining tool false positives carry precisely scoped justifications.

1.0.253

  • Escaping conformance polish on a handful of remaining literal outputs ahead of the WordPress.org re-review. No functional changes.

1.0.252

  • Job board: Call / Text / Email on lost leads are now one tidy segmented control with icons, and History steps back visually. Invoice page: the action bar is decluttered (Print, Email, Mark as Paid stay up front; Copy customer link, the AI reminder, and the pay link live under More Actions), the AI-drafted reminder can now be sent directly from the page after review (logged to the communications history), and “Email to customer” asks before its immediate send. Quote builder: the AI description tools no longer vanish on short text; they show disabled with a note that they unlock at 200 characters.

1.0.251

  • Audit follow-ups: settings saves no longer strip literal backslashes from typed text (double-unslash regression in 1.0.249); the van icon and link-arrow SVGs keep their shading and rounded strokes through output escaping; photo caption line-clamping is preserved; Stripe key diagnostics render their formatting again; several links now use the exact right escaper for their context; the calculator nonce is scrubbed from the address bar after a Calculate. Business Checkup items gained one-click action links (Create invoice, Log hours) and invoice photos now display two-up at half width.

1.0.250

  • Fixes from live testing of 1.0.249: HTML badges and notices that rendered as raw markup (job view title badges, financials accordion summaries, Estimate vs Actual variance column, business/vehicle notices, worker hour dropdowns) now escape through the correct HTML-aware helper; sms: and webcal: links survive output escaping; and a latent fatal on the Business Checkup page (only triggered once a completed job had a balance due) is fixed.

1.0.249

  • Security hardening for the WordPress.org plugin review. Every database query now goes through $wpdb->prepare() with %i table-identifier placeholders (WordPress 6.2+, “Requires at least” raised to 6.2 accordingly). All plugin-built HTML is escaped at the point of output through a central wp_kses allow-list; the settings pages sanitize every submitted array at intake and uploaded files are sanitized before the upload handler. The trade-calculator state and the settings deep-open links now carry nonces. The service worker, the customer quote/invoice page styles, the payment-finalizing poll, the printable report styles, and the report PDF renderer all moved out of inline tags into enqueued asset files. The legacy rl_resource post type was renamed to paintops_resource (with an automatic one-time migration of existing entries, including their URL field) and the [resource_links] shortcode is now [paintops_resources]; if you placed the old shortcode in a page, update it. The Freemius bootstrap accessor was renamed from pai_fs() to paintops_fs().

1.0.248

  • Fix (Pro): a stray test clock-in with almost no time on the clock could produce absurd Profit / Hour figures (tens of thousands per hour) on the job financials, reports, and rankings. Rates past a plausibility cap (default $3,000/hour, filterable) now display as a dash instead, such jobs are excluded from the Profit Per Hour rankings, and the AI profit explainer is told the rate is not meaningful rather than being fed the bad number.

1.0.247

  • Fix (Pro AI): the AI rewrite and photo estimator no longer add a “Description of Work” heading on top of their text; the quote already prints that heading itself. The model is instructed to skip it, and any heading that slips through is stripped before the text reaches the editor.

1.0.246

  • Fix: the Description of Work / Inclusions saved from the quote editor lost all its formatting (line breaks, bold, lists) the moment the quote was created, displaying as one run-together paragraph. The editor’s rich text is now preserved on save while still stripping anything unsafe. Quotes saved while the bug was live need their description re-entered once; new saves keep formatting.

1.0.245

  • WordPress.org plugin review round 1 response. The free plugin is now fully functional with no locked features: the monthly job/quote cap is removed (unlimited jobs and quotes on free), and all Pro-only code (Stripe payments, AI tools, profit reports, vehicle and business tracking) ships only in the Pro build rather than sitting locked in the free one.
  • The “Powered by PaintOps” credit on quotes and invoices is now strictly opt-in for everyone: it stays off unless you turn it on under Business Settings > Quote & Invoice Branding.
  • All of the app’s CSS and JavaScript now loads through the WordPress enqueue system (as static asset files plus small dynamic fragments) instead of inline style/script tags, per WordPress.org guidelines. Customer-facing standalone documents (public quote/invoice pages, printable reports) keep their self-contained styling by design.
  • Documented the Resources page’s YouTube/Vimeo video embeds in the readme’s External services section.
  • Hardened input sanitization (quote overflow line items, time-off form) and output escaping (time-off notices, upload error details) in several spots.

1.0.244

  • When the app is offline and shows a saved copy of a page, it now says so: a banner at the top shows when the copy was saved, warns that anything scheduled since then is not shown, and the page refreshes itself the moment the connection comes back. Before this, an offline snapshot looked exactly like live data, which could read as a job missing from the calendar.

1.0.241

  • Fix: the Painters/Helpers admin table did not fit small screens and could not be used on mobile. It now scrolls horizontally within its own container, matching every other wide admin table in the plugin.
  • Fix: a Callback or Punch List visit with no billable amount of its own, since it exists to finish or warranty its parent job rather than stand as its own job, could still show up as an entry in the “Bottom 3 Jobs” profit ranking (Pro). Non-billable callback and punch list visits no longer count as their own ranked job; a billable callback or punch list still does.

1.0.240

  • Fix: a Painter/Helper opening the app’s plain web address instead of a specific job link saw “Please log in to access PaintOps” even while already signed in, and had no way in except a job’s night-before email link. They now land on their “My Jobs” home (today, upcoming, and anything needing attention), a page that already existed for this but could not be reached from the plain address before.
  • A worker’s “My Jobs” home now has a Past Jobs list too, every completed job or visit they were on, so there’s a way back to an old job for a note, a still-needed receipt, or a callback follow-up.
  • Adding a receipt to a job now offers AI scanning first, same as the Vehicle Log: choose “Scan Receipt with AI” and the photo picker opens right away with the scan running as soon as a photo’s picked, or choose “Manually Enter” for an empty form. (Pro with AI configured only; unchanged otherwise.)

1.0.239

  • Fix: the offline app cache could get stuck showing a stale “please log in” screen for a job page even after the worker signed back in, because the background cache refresh skipped re-fetching any page it had already saved once. It now always refreshes the saved copy in the background, so offline job pages stay current with the worker’s actual signed-in state.

1.0.238

  • Fix: the job Time Clock (check-in/check-out) could display times up to several hours off from the actual time on servers where another plugin changes PHP’s default timezone, the “Checked in at” confirmation was correct but the “Checked in since” status line, the recent time-on-this-job list, and the checkout note could all be wrong. All check-in/check-out time displays now render consistently and correctly.

1.0.237

  • Fix: Plugin URI and Author URI headers no longer share the same value (wp.org submission requirement); Author URI now points to the founder’s story page.

1.0.236

  • Code review annotation added to the new routing rescue file. No functional changes.

1.0.235

  • All date displays are now immune to other plugins or themes overriding PHP’s timezone. Previously, if anything on the site changed PHP’s default timezone away from UTC (WordPress pins it to UTC, but some plugins override it), every PaintOps date rendered between midnight and the early morning hours could show the previous day, the Jobs page, calendar, and reports now show the correct site-local date regardless.

1.0.234

  • The Jobs page now computes “today” exactly once per page load using the WordPress site clock, so the Today widget and the job board can never disagree, previously a page rendered while the site’s clock crossed midnight could say “nothing scheduled today” above a card marked “started today”.

1.0.233

  • Reactivate License buttons and rescued permission errors on an unlicensed Pro install now open the Plugins page, where the Activate License link under PaintOps works in every license state, with a bold pointer added under the button.

1.0.232

  • On a Pro install that is waiting for its license key, the Upgrade to Pro buttons now read Reactivate License and open the license screen directly, matching what the user actually needs to do in that state. The free version’s upgrade buttons are unchanged.

1.0.231

  • The “Sorry, you are not allowed to access this page” dead-end is gone: if an Upgrade link lands on a licensing page that does not exist in the site’s current license state (most commonly on a Pro install waiting for its license key after a reinstall), PaintOps now catches the error and opens the main PaintOps admin page, where the license screen appears whenever a key is needed.

1.0.230

  • Upgrade buttons now route by license state: on an already-licensed site they open the Account page, and on the Pro build awaiting its license key (for example right after a reinstall) they open the license activation screen. Both cases previously dead-ended on a WordPress permissions message.

1.0.229

  • Release build: everything through the Plugin Check zero, the premium package fix, and the address autocomplete fix. The upgrade-link routing refinements from 1.0.224/1.0.225 are deferred (edge cases around stale pages only) while a build tooling issue is investigated with Freemius.

1.0.228

  • Same upgrade-button routing as 1.0.225, reformulated for the build tooling. No functional changes.

1.0.227

  • Same as 1.0.225 (upgrade buttons route by license state) with the code annotations around that change simplified for the build tooling. No functional changes.

1.0.225

  • On the Pro build without an active license, the Upgrade to Pro buttons now open the license activation screen (where entering your key is the actual upgrade step) instead of a pricing page that does not exist in that state.

1.0.224

  • On a site that already has an active Pro license, any leftover Upgrade link (for example on a page rendered just before the license was activated) now opens the Account page instead of a WordPress “not allowed” error, since the pricing page does not exist once a site is paying.

1.0.223

  • Address autocomplete no longer randomly fails to start on the job and customer forms. The Google Maps script loads asynchronously and could occasionally finish before the page had defined the function it calls back into; the loader is now printed after that function and uses Google’s recommended loading=async parameter, so the race cannot happen.

1.0.222

  • Build fix for the premium package: the vehicle and business expense report pages (with their printable coversheet templates and the PDF receipt printing panel) moved from the main plugin file into includes/pro-expense-reports.php. The premium build generator re-emits the main file through a code printer that cannot handle raw HTML template sections inside a premium-only block, which is what produced the empty main file. Include files are packaged verbatim, so the reports are unchanged in behavior on both tiers.

1.0.220

  • Build fix attempt for the premium package: the closing comments on the premium-only blocks in the main …