Title: PaintOps
Author: paintops
Published: <strong>July 29, 2026</strong>
Last modified: July 29, 2026

---

Search plugins

![](https://ps.w.org/paintops/assets/banner-772x250.png?rev=3627427)

![](https://ps.w.org/paintops/assets/icon-256x256.png?rev=3627427)

# PaintOps

 By [paintops](https://profiles.wordpress.org/paintops/)

[Download](https://downloads.wordpress.org/plugin/paintops.1.0.265.zip)

 * [Details](https://wordpress.org/plugins/paintops/#description)
 * [Reviews](https://wordpress.org/plugins/paintops/#reviews)
 *  [Installation](https://wordpress.org/plugins/paintops/#installation)
 * [Development](https://wordpress.org/plugins/paintops/#developers)

 [Support](https://wordpress.org/support/plugin/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.

## 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

 *   [ paintops ](https://profiles.wordpress.org/paintops/)
 *   [ Freemius ](https://profiles.wordpress.org/freemius/)

[Translate “PaintOps” into your language.](https://translate.wordpress.org/projects/wp-plugins/paintops)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/paintops/), check out
the [SVN repository](https://plugins.svn.wordpress.org/paintops/), or subscribe 
to the [development log](https://plugins.trac.wordpress.org/log/paintops/) by [RSS](https://plugins.trac.wordpress.org/log/paintops/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 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 file no longer repeat the premium marker text, so the
   build tool sees exactly one marker per real block. No functional changes.

#### 1.0.218

 * Build fix attempt for the premium package: the Freemius init array is now free
   of inline comments (one of them contained the exact token the premium build step
   is documented to remove, and that step regenerates this array). No functional
   changes.

#### 1.0.217

 * Plugin Check: the last 5 findings closed. The build generator splits compact 
   one-line statements across lines, which pushed three footer outputs and the app-
   page lookup’s meta arguments out from under their review annotations; each annotation
   now sits directly above the exact line it covers, in a structure the generator
   preserves. No functional changes.

#### 1.0.216

 * Build fix: the plugin header comment is back at the very top of the main file,
   ahead of the code review annotations added during the Plugin Check cleanup. The
   premium build generator requires the header there and was producing an empty 
   main file, which made the premium zip uninstallable (“No valid plugins were found”).
   No functional changes.

#### 1.0.215

 * New workers are no longer stranded at the door: the “Please log in to access 
   PaintOps” screen now shows a Log In button that takes them to the login form 
   and returns them to the exact page they were opening, including the specific 
   job from a job notification email. The job notification email also mentions what
   to do if the login screen appears.

#### 1.0.214

 * Plugin Check round two: the 204 findings that survived 1.0.213 are closed. The
   build tool that produces the free version rewrites statements and relocates end-
   of-line comments, which silently disabled many of the 1.0.213 review annotations;
   all annotations in rewritten files now sit on their own line above the code they
   document, where the build preserves them. More real hardening while at it: pricing-
   rule numbers, company profile dropdowns, proxy-header reads, and the form replay
   token are now fully sanitized and unslashed at the source; every URL echoed on
   admin screens goes through esc_url() at output; month options, crew ids and diagnostic
   messages are cast or escaped at output.

#### 1.0.213

 * Plugin Check cleanup pass: every remaining finding resolved. Real hardening fixes:
   nonce values are now sanitized and unslashed before wp_verify_nonce() everywhere,
   quote titles, supply descriptions and work descriptions are sanitized and unslashed
   on save (also fixes apostrophes storing as \’ in quotes), payment/invoice tokens,
   routing parameters and time-off fields are sanitized, job IDs and crew IDs cast
   to integers in output, Google Earth links escaped with esc_url(). Everything 
   intentionally left as-is (plugin-owned tables via $wpdb, pre-escaped HTML builders,
   whitelisted dropdown values, integer casts) now carries a written justification
   for reviewers.

#### 1.0.212

 * Fix: the free plan no longer offers or defaults to “Card deposit online” on the
   job form (online card deposits ride on Stripe, a Pro feature). Free records default
   to the cash/check deposit plan; a record already set to the online plan keeps
   it visible when editing.

#### 1.0.211

 * Improve: the PDF-receipt print panel now has an adjustable “Pages per PDF” cap,
   default 30 (was a fixed 15), so long multi-receipt PDFs render in full.

#### 1.0.210

 * New (Pro): the Business Financial Report’s receipt version can now print PDF 
   receipts in one pass. A floating “Render PDFs for printing” button converts every
   attached PDF into pages right inside the report, so a single browser Print captures
   the whole stack, no more opening each PDF by hand. Anything that fails to render
   keeps its placeholder card and open link.

#### 1.0.209

 * Improve: in Taxes & Filing, the receipt search now sits above the job coversheets,
   and the Find Duplicates button wears amber so it reads as the problem-hunting
   tool it is. The Business Financial Report defaults to totals only, the way accountants
   actually file, with a separate “+ Receipt Images” button for the full audit file;
   the “Receipts attached” checklist line only prints on that version.

#### 1.0.208

 * Improve: the Business page now uses the same collapsible sections as the rest
   of the app. Painters/Helpers, Vehicles, Business Expenses & Overhead, Taxes &
   Filing, and Backup & Data each collapse to a header with a glance line (roster
   count, vehicle count, expense totals, tax buckets), and the section you just 
   acted on, saving vehicle owners, logging an expense, switching the year, or running
   a receipt search, opens automatically so the result is on screen.

#### 1.0.207

 * New: a duplicate finder next to the receipt search. One click scans the whole
   year for expenses sharing the same date and amount, groups them, flags same-job
   same-vendor pairs as “Likely duplicate”, and links each entry’s receipt image
   and job so you can verify before removing anything.
 * Improve: the vehicle expense form (gas receipts) now matches the job Add Expense
   flow, receipt photo/PDF and the AI scan at the top, details below.

#### 1.0.206

 * Improve: the receipt search now suggests where to file an unmatched paper receipt.
   Under the results, “Holding a receipt that isn’t listed?” lists jobs that were
   working around the searched dates, jobs with crew hours actually logged in the
   window sort first (the strongest signal someone was on site buying materials),
   with the scheduled work window as the backup signal, and a one-click “File Receipt
   Here” button on each.

#### 1.0.205

 * Improve: the receipt search’s checkmark now opens the receipt file itself (“View
   receipt”, with numbered links when an expense has several files), and searching
   updates the results in place without reloading the Business page. If scripts 
   are unavailable the plain submit jumps straight back to the search section.

#### 1.0.204

 * New: Receipt search on the Business page, under the job receipt coversheets. 
   Pick a date range and see every logged job expense in it, with vendor, category,
   amount, the job it’s tied to, and whether a digital copy is attached, built for
   checking a stack of paper receipts against the books.

#### 1.0.203

 * Improve: board headers switched to the accent-underline style, a short stage-
   colored bar under each title with the count in a matching solid pill (icons removed).

#### 1.0.202

 * Improve: the Job Board column headers got their new look, a stage icon (inbox,
   roller, check) with the count as a solid color pill, steel blue for Requests,
   green for Active Jobs, gray for Completed, matching the card stripe palette.
 * Fix: the night-before job email no longer says “0 Day Job Begins Tomorrow” for
   visits saved without a day count, it floors to 1.

#### 1.0.201

 * Improve: every customer-contact tap now lands in the communications log, Call/
   Text/Email in the Not Won drawer, the job page’s customer Call/Text reveal, Call
   Customer and Text Customer in the job actions menu, and the Text Follow-Up nudge,
   alongside the quote email sends and Text Quote taps already logged. Each entry
   is honest about what it records: phone and mail links open the app, so the tap
   is what gets logged. Team-member Call/Text stays unlogged on purpose, that’s 
   coworker contact, not customer history.

#### 1.0.200

 * Improve: the board’s three columns now start their cards on the same line (the
   glance slot under each header is fixed-height), status pills say Bid or Estimate
   when that’s what the record is (“Bid Created” instead of “Quote Created”), and
   request cards show a green “Emailed Jul 20th / Texted Jul 21st” line from the
   communications log. Tapping a Text Quote/Bid link now logs the tap (delivery 
   itself can’t be tracked from an sms: link), and emails were already logged on
   send. The Not Won drawer gained Call / Text / Email links plus a History drawer
   on every lost lead, shown even when empty.

#### 1.0.199

 * Improve: Job Board polish pass. Requests sort by urgency (overdue visits first,
   then stale quotes, then newest). Each column header shows a glance line like “
   1 overdue visit” or “2 unpaid, $3,150 outstanding” (dollar figures only for financial
   viewers). Every column now collapses its long tail behind a show-more drawer 
   with the fetch limit raised to 50. On phones, Active Jobs stacks first, columns
   collapse on tap, and Completed starts collapsed. Empty columns teach the flow
   instead of saying “Nothing here.”

#### 1.0.198

 * Improve: every Job Board card (Requests, Active Jobs, Completed) now leads with
   one stripe that says it all, like “Upcoming – Starts Tomorrow Jul 24th”, “Scheduled
   4 Days Ago Jul 19th” (amber once a visit date slips), or “Completed Jul 20th”,
   and the separate date line is gone. The whole upper card is now one big link 
   to the job view, replacing the name link and the View Job footer link.
 * Fix: records marked Not Won no longer appear on the Calendar (they still live
   in the board’s Not Won drawer). Punch-list and callback visits now copy the parent
   job’s State field, and the customer page merges address variants that only differed
   by a missing state, so no more duplicate “Other addresses on file”.

Older entries: the full version history ships with the plugin’s development notes
and on paintoperations.com.

## Meta

 *  Version **1.0.265**
 *  Last updated **1 day ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.2 or higher **
 *  Tested up to **7.0.2**
 *  PHP version ** 7.4 or higher **
 * Tags
 * [contractor](https://wordpress.org/plugins/tags/contractor/)[estimates](https://wordpress.org/plugins/tags/estimates/)
   [invoicing](https://wordpress.org/plugins/tags/invoicing/)[painting](https://wordpress.org/plugins/tags/painting/)
   [scheduling](https://wordpress.org/plugins/tags/scheduling/)
 *  [Advanced View](https://wordpress.org/plugins/paintops/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/paintops/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/paintops/reviews/)

## Contributors

 *   [ paintops ](https://profiles.wordpress.org/paintops/)
 *   [ Freemius ](https://profiles.wordpress.org/freemius/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/paintops/)