Changelog
Release notes & version history for Freelance Studio
Version 9.5.3
6 changes
▼
- New: Archive estimates. Estimates can now be archived from the estimate list row menu and the estimate view actions. Archived estimates are hidden from the default Estimates list and only appear when you select the new Archived option in the status filter; viewing an archived estimate offers an Unarchive action that restores its prior status (converted, declined, approved, sent, or draft) based on its recorded history.
- New: Delete declined or orphaned estimates. Previously a converted estimate could never be deleted. You can now delete an estimate when it is not converted, when it has been declined, or when it was converted but its resulting invoice has since been deleted (orphaned). This is enforced both in the UI and server-side in the delete handler.
- New: Estimate-specific "viewed" notification email. When a client first opens an estimate you now receive an estimate-worded notification ("Estimate Viewed", estimate total, and a Valid Until line when set) with a View Estimate button, instead of the invoice-worded email that previously showed a bogus due date.
- Changed: "Payment Terms" label on estimates. Estimates now show "Payment Terms" in place of "Payment Instructions" in the estimate view and the estimate PDF; invoices keep "Payment Instructions".
- Changed: "Powered by Freelance Studio" email footer now links to the site. The internal-notification email footer links "Freelance Studio" to https://freelancestud.io across all plugin emails that use the shared wrapper.
- Polish: Estimate list and dashboard UI. Estimate status dropdowns now use the same colored pill styling as invoices, and the dashboard "Your Week at a Glance" day cells wrap onto a second row when the card is shown at a narrow width.
Version 9.5.1
2 changes
▼
- New: Estimates dashboard card. The dashboard now includes an Estimates card showing how many estimates are awaiting client approval and how many are open overall, with a link straight to the Estimates tab in Finances. It's available in the default dashboard layout and the customizer card list like any other card.
- Changed: Estimates no longer include Billable Expenses. The expense bill-back section has been removed from the estimate form — estimates are a quick price quote, so project expenses are billed on the resulting invoice instead, not on the estimate.
Version 9.5.0
6 changes
▼
- New: Estimates. You can now send clients an itemized price quote that they approve with a single click, then convert 1:1 into an invoice. Estimates live in a new Estimates tab in the Finances area, next to Invoices, with a count badge when any are awaiting approval. They share the invoice engine — line items, totals, tax, discounts, the PDF renderer, the public token link, and email sending — so there's no separate, drift-prone machinery to maintain. Under the hood, estimates are stored in the existing invoices table behind a new
doc_typecolumn (invoice|estimate); every financial query defaults todoc_type = 'invoice', so estimates never count as income, accounts receivable, or tax, and the dashboard, reporting, tax, client charts, and recurring logic stay correct automatically. Estimates use a separate numbering sequence (EST-prefix by default), have a Valid Until date instead of a due date, and auto-expire after that date via the existing daily cron. The full lifecycle is draft → sent → viewed → approved (or declined / expired) → converted. - New: Public click-to-approve. The client-facing estimate page shows Approve and Decline buttons (with an optional decline reason) instead of Pay Now, plus the validity date. Approval and decline are handled over AJAX, validated by the estimate's view token — no client login required. You're notified by email when a client approves or declines. There's no e-signature step (estimates are a quick quote, not a contract).
- New: Convert to invoice. An approved estimate converts into a fresh draft invoice in one click, copying the client, project, line items, expenses, tax, discount, and notes, and assigning a new invoice number. The original estimate is kept for history and linked to the invoice it produced. Auto-conversion on approval is available as a setting but is off by default so you can review before converting.
- New: "Send an estimate for this project?" at project creation. When creating a new project, a checkbox in the Billing section builds an estimate pre-filled from the project's services (description, quantity/hours, rate, amount), sets the validity date from your default, and drops you on the estimate edit screen to review before sending — choose draft or send-now.
- New: Estimate settings on the Invoices settings tab — estimate number prefix, next number, default validity period (days), default estimate terms, and the auto-convert-on-approval toggle.
- Note: Estimates are available on all plans and estimate sends are unlimited — they do not count toward the free plan's monthly invoice-send limit.
Version 9.4.0
2 changes
▼
- New: Hide cards from the dashboard. Customize mode now has an eye icon on each card's drag handle. Click it to hide a card you don't use; hidden cards drop out of the dashboard while keeping their place in the layout. A "Hidden cards" tray appears beneath the customize bar listing everything you've hidden — click any chip to restore that card to exactly where it was. Hidden state is saved per user alongside the layout (the
fs_dashboard_layoutuser meta gains ahiddenlist), and "Reset to Default" clears it. No widget data is lost; hidden cards are simply not displayed. - Changed: New default dashboard layout (before any customization). The out-of-the-box arrangement was reordered to surface the most-used cards first. Main column: Financial Overview, This Week, Tasks, Invoices, Action Needed, Recent Projects, Pending Proposals, Awaiting Signature. Sidebar: Quick Actions, Calendar, Upcoming Events, Time Tracker, Recent Sessions, Time Goals. The internal-tasks card (when internal tracking is enabled) now inserts immediately after Time Goals regardless of position, instead of at a hardcoded slot. Existing users who have already customized their dashboard are unaffected — this only changes the starting layout for new users and after a layout reset.
Version 9.3.1
2 changes
▼
- Changed: The digest preview and test email now render from the exact same builder as the real weekly email. Previously the settings-page preview and the test email each maintained their own near-duplicate copy of the digest markup, so they could drift from what actually gets sent (and from each other). Both now call
FS_Google_Calendar_Service::build_digest_email_html()— the single source of truth — and the duplicaterender_digest_preview()method was removed. The preview displays the full email document inside an iframe so headers, body styling, and footer render faithfully. - New: "Fill with sample data" checkbox on the digest preview. By default the preview and test email now show your real upcoming week, exactly as the Monday email will. Ticking "Fill with sample data" swaps in placeholder content instead — useful for seeing a fully populated example before you've added projects, invoices, or meetings. The choice is passed through to both the Show Preview and Send Test Email actions.
Version 9.3.0
1 change
▼
- New: "Upcoming Meetings" section in the Week Ahead digest. The weekly digest email now leads with an Upcoming Meetings section listing booked meetings scheduled in the next 7 days, shown above Invoices Due. Each entry shows the meeting type, the client/guest name, and the day and time; pending bookings carry a "Pending" badge. Both confirmed and pending bookings are included. The section is sourced from
fs_bookings(joined to meeting types and clients) inFS_Google_Calendar_Service::generate_weekly_digest(), with matching sample data inget_demo_digest()so the settings preview and test email render it too. When there are no items at all across every section, the digest still shows the "All Clear!" message.
Version 9.2.0
4 changes
▼
- New: Active / Archived tabs on the project Tasks tab — The Tasks tab inside a project now has Active and Archived sub-tabs (matching the global Tasks list). Active is shown by default and excludes archived tasks; Archived lists archived tasks with a count badge. Previously every task, including archived ones, rendered together with no way to separate them.
- New: Client portal invoice filtering & pagination — The Invoices tab in the client portal now has a filter bar (Status: All / Paid / Unpaid, a Year dropdown, and a From/To date range) and paginates at 10 invoices per page with a result summary and page controls. Filtering and paging happen instantly in the browser; a "Clear" button resets all filters. Previously every invoice was listed in one long unpaginated table.
- Fixed: Archived tasks were counted as "Completed" in the project task overview, inflating the completed count and the Overall Progress percentage. Archived tasks are now excluded from the active view and no longer counted toward completion.
- Fixed: The client portal project view listed archived tasks.
get_project_tasks()now excludes tasks with anarchivedstatus so clients only see live tasks.
Version 9.1.0
1 change
▼
- New: Notify client when a task is done. Completed tasks (in the Kanban Done column and in the task list when status is Completed) now show a small paper-airplane icon. Clicking it opens a "Notify client?" modal with the client's primary email and contacts pre-listed as checkboxes — pick one or more, hit Send notification, and the client gets a styled email letting them know the task is done (with task title, description, project, and completion date). Includes the client portal link when portal access is enabled. New AJAX action
fs_notify_client_task_completeplusFS_Email_Service::send_task_completion_notification(). The shared modal partialincludes/views/partials/notify-client-task-modal.phpis reused across views. The icon and notification correctly resolve a task's client whether it's linked directly (tasks.client_id) or inherited from its project (projects.client_id) — project-only tasks were silently missing the icon in an earlier internal build.
Version 9.0.13
3 changes
▼
- Fixed: Client dashboard (Client view page) tabs, links, and buttons were unclickable. The Add Contact modal in
includes/views/clients/view-tabs.phpwas missing two closingtags after its, leaving#fs-contact-modaland.fs-modal-contentopen. The closinginview.php(intended to close.fs-tab-contentand.fs-wrap) were instead absorbed by the open modal, leaving the page wrapper divs unclosed and breaking the layout. Added the missing closing tags so the modal closes properly and the page wrapper divs close where they should. - Fixed: Apostrophes and quotes in Project Services name/description were saved with a backslash escape (e.g.
AP'sdisplayed asAP\'s). Thefs_update_project_servicesAJAX handler was sanitizing$_POST['services']without first callingwp_unslash(), so WordPress's auto-added magic quotes survived into the stored value. Now unslashes the services payload before sanitizing. Existing records will be cleaned up next time they're re-saved. - Fixed: Editing an invoice that had been marked as paid silently rewrote its
due_dateto "today + 30 days." On the invoice form, the page-load$('#client_id').trigger('change')fired the same handler used when the user manually changes the client — which callsfs_get_clientand overwrites#due_datewith the client's default payment terms. Added afsInitialClientLoadguard so the page-load trigger skips the due-date AJAX update; the recalculation only runs when the user actually changes the client.
Version 9.0.12
1 change
▼
- Fixed: The selected "To" radio in the send-email modal still showed an empty teal ring with no inner dot. The cause was WordPress admin core's own
forms.css, which paints aninput[type="radio"]:checked::beforewhite dot on top of the control — covering the radial-gradient dot added in 9.0.11. The modal's custom controls now suppress that core::beforepseudo-element (via a higher-specificity rule, no!importantneeded) so the teal dot renders correctly.
Version 9.0.11
1 change
▼
- Fixed: A selected "To" radio button in the send-email modal showed only a teal outline with no inner dot, making it hard to tell which contact was the direct recipient. The 9.0.10 fix used an inset white box-shadow to carve out the dot, but WordPress admin core's own radio styling left the interior white. The selected dot is now drawn with a radial gradient (the same reliable approach used for the CC checkmark) and renders correctly in both standard and high-contrast modes.
Version 9.0.10
18 changes
▼
- Fixed: In the Send Invoice / Send Contract / Send Proposal email modal, the To radio buttons and CC checkboxes did not visually indicate their checked state. The custom controls used
appearance: nonebut had no border in their default state and no checked-state styling (the radio relied onaccent-color, which has no effect onceappearance: noneis set, and the checkbox had no checked rule at all), so selected and unselected options looked identical. The controls now render a visible border by default, a filled teal dot when a radio is selected, and a teal box with a white checkmark when a CC checkbox is ticked, plus a keyboard focus ring and high-contrast overrides. - Changed: CC recipients in the send-email modal are now opt-in. Previously every additional client contact had its CC checkbox pre-checked, so sending the email copied all contacts unless they were manually unticked — which, combined with the invisible checked state above, meant recipients were CC'd without the sender realizing. Additional contacts now start unchecked; the primary contact remains the default To recipient. This affects the shared modal used by invoices, contracts, and proposals.
- Security: Added
if ( ! defined( 'ABSPATH' ) ) exit;direct-access guards to every plugin PHP file that lacked one (controllers, services, helpers, models, view partials, and silence stubs). 67 files in total, restoring the WordPress convention that PHP files should not be executable when accessed directly via URL. - Security: Wrapped every
sanitize_text_field()/sanitize_email()/sanitize_textarea_field()/sanitize_key()/esc_url_raw()/sanitize_hex_color()call that reads$_GET/$_POST/$_REQUESTwithwp_unslash()first, since input superglobals carry magic-quote slashes that must be removed before sanitization. ~167 sites across controllers, AJAX handlers, frontend router, and views. - Security: Hardened the SQL
'{$today}'interpolations inclass-fs-task.php(smart-recurring filters in both list and count queries, and the recurring-parents query) by switching to$wpdb->prepare()with%splaceholders. The$todayvalue comes fromcurrent_time('Y-m-d')and was never user-controllable, but interpolation-style queries are flagged by static analysis even when safe; using prepare removes the warning and matches WP coding standards. - Security: Converted ~53 schema-introspection queries in
class-fs-migrator.php(SHOW TABLES LIKE,SHOW COLUMNS FROM ... LIKE,INFORMATION_SCHEMA.COLUMNSlookups) to$wpdb->prepare()with%splaceholders for value comparisons. Identifier interpolations in DDL statements (e.g.ALTER TABLE {$table}) cannot be parameterized but use only internal hardcoded values. - Security: Sanitized
$_POST['payments']array source in bothclass-fs-finances-controller.php::save_quarterly_payments()andclass-fs-settings-controller.phpbefore iteration: now wraps withwp_unslash, validatesis_array, forces the quarter key throughintvaland rejects values outside 1–4. Inner amount/date sanitization (already present) is unchanged. - Security: Sanitized
$_POST['expenses']array source inclass-fs-invoices-controller.phpwithwp_unslashbefore iteration. Each$expense_idwas already cast throughintval. - Security: Sanitized the
$_POST['signature_data']/$_POST['signature']raw read inclass-fs-frontend-router.php::ajax_sign_proposalwithwp_unslashat the entry point. Content sanitization continues throughFS_Security_Service::sanitize_signature()which validates the base64 data URI format.sanitize_text_fieldis intentionally NOT used here because it would strip valid characters from the base64 payload. - Security: Sanitized the
$_GETarray passed toadd_query_arg()inclass-fs-admin.php::handle_early_redirects(). Each value is now wrapped withwp_unslashandsanitize_text_field, and the result is passed throughurlencode_deep()before being merged into the redirect URL, per WP coding standards. - Security: Sanitized the
$_GETfilter inputs inkanban.php,projects/list.php,tasks/list.php,proposals/view.php,expenses/list.php,bookings/list.php,invoices/list.php,settings/index.php, and thetime-tracking-controller.php::reports()and::form()methods withwp_unslash+ appropriate sanitizer. These are read-only filter parameters so no nonce is required, but consistent unslashing matches WP coding standards. - Security: Replaced the
echo $html;infreelance-studio.php::fs_studio_pro_upgrade_html()withecho wp_kses_post($html);, and upgraded the bare__()calls inside (Upgrade-to-Pro / Upgrade-Now CTA labels) toesc_html__(). Each piece composing the HTML is individually escaped at construction, withwp_kses_postas the safety net at the output boundary. - Security: Replaced
echo $html;inclass-fs-admin.php::export_tax_deductions_pdf()(the downloadable HTML fallback for the tax-deduction summary) withecho wp_kses_post($html);. - Security: Restructured the dynamic
emission inclass-fs-view-context.php::render_custom_activity_css()so theopener and closer are literal strings and the CSS body (built fromsanitize_key'd activity slugs and a hard-coded color palette) is passed throughwp_strip_all_tags()as belt-and-suspenders. - Security: Wrapped 11
printf( __('...%s...'), ... ); // phpcs:ignorepatterns with proper escape functions, eliminating everyWordPress.Security.EscapeOutput.OutputNotEscapedignore comment in the codebase except the two intentional ones for raw PDF binary output (class-fs-pdf.php) and CSV download streams (class-fs-forms-controller.php). Plain-text translations now useesc_html__(); translations containing inline HTML (e.g. the bookings availability time-zone notice withandtags, the invoice "no-payment-link" notice with edit/settings anchors) usewp_kses()with explicit allowed-tag arrays. - Security: Escaped
echo $task->id;inclients/view.php(data-attribute context, ×2) withesc_attr(). - Reliability: Paired the long-lived
ob_start()inclass-fs-admin.php::handle_early_redirects()with an explicitadd_action('shutdown', ...)close. The buffer is intentionally left open across the request lifecycle so controller-levelsafe_redirect()calls can clean output before sending headers, but the shutdown hook now guarantees the buffer stack stays balanced even when no redirect runs and the request renders normally. - Build: Bumped plugin header version and
JEEB_FS_VERSIONconstant to 9.0.9 and updatedreadme.txtStable tag.
Version 9.0.7
2 changes
▼
- Improved: The projects list bulk-archive toolbar is now always visible above the projects table — previously the toolbar only appeared after a checkbox was ticked, so the bulk-action capability was hard to discover. The Archive Selected (or Restore Selected, on the archived tab) button is disabled until at least one project is checked.
- New: A "Select all *N* matching this filter →" link now appears in the bulk toolbar once every checkbox on the current page is selected and additional matching projects exist on other pages. Clicking it selects every project across all pages that match the current filter (status, client, billing type, archived tab) so the entire set can be archived in a single operation. Useful when archiving large batches of imported projects without paging through them one at a time.
Version 9.0.6
1 change
▼
- Improved: Approved proposals now show a single "Convert ▾" dropdown button in place of the separate "Convert to Contract" and "Create Project" buttons, giving a clear next-step decision point with two options: Convert to Contract (the existing contract-conversion flow) and Convert to Project (creates a project pre-filled from the proposal's client, title, services, and deposit terms). Once a contract has been generated for the proposal, the dropdown collapses back to a single "Convert to Project" button.
Version 9.0.3
2 changes
▼
- Updated: Bundled Chart.js library upgraded from v4.4.1 to v4.5.1 (
admin/js/vendor/chart.umd.min.js). This is a minor-version update within the same major release, so the public API is unchanged and no chart configurations needed adjustment. The upgrade addresses the WordPress.org reviewer's flag for an out-of-date third-party library. - Changed: Freemius SDK initialization now sets
is_org_compliant => true. This flag is required by WordPress.org reviewers for directory-hosted Freemius-integrated plugins and disables SDK features that conflict with WP.org guidelines (such as Freemius-hosted contact and support menu items). The flag affects the free build only; the Pro build's behavior is unchanged.
Version 9.0.2
7 changes
▼
- Security: Replaced eight
stripslashes($_POST[...])calls withwp_unslash()and addedisset()guards inclass-fs-ajax-handler.php(dashboard widget layout, client/invoice/project import lookups, transaction batches, categorization rules). Decoded JSON arrays are also now passed througharray_map('sanitize_text_field', ...)before being used in database queries, providing defense in depth even though the values flow through$wpdb->prepare(). - Security: Sanitized
$_GETfilter inputs in the expenses list view (includes/views/expenses/list.php) before echoing them. The values were previously only escaped (esc_attr) without being sanitized first; per the WordPress.org plugin guidelines, escaping is not a substitute for sanitization. Now wrapped withsanitize_text_field( wp_unslash( ... ) )and pre-computed once at the top of the form block. - Security: File uploads now derive MIME types from the file extension via
wp_check_filetype()rather than trusting the client-supplied$_FILES[...]['type']value. Affects the bug-report screenshot uploader (class-fs-admin.php) and the Pro form-response file upload handler (class-fs-frontend-router.php). The form handler also now wraps the$_FILES[...]['name']value withsanitize_file_name( wp_unslash( ... ) )before passing it through. - Documented: Added a comment to the Google Calendar webhook REST route registration (
class-fs-google-calendar-service.php) explaining why the endpoint usespermission_callback => '__return_true'— the endpoint receives push notifications from Google's servers (not authenticated WordPress users) and validates incoming requests via the Google-suppliedX-Goog-Channel-IDheader against a stored channel ID. - Changed: Replaced the inline
document.body.classList.add('fs-kanban-page');block in the kanban tasks view with anadmin_body_classfilter that adds the class server-side. Removes one of the inlinetags flagged in the WordPress.org review. - Changed: Rewrote the readme's
== External Services ==section to accurately document all four optional external services the plugin can connect to: Brevo (email delivery), Postmark (email delivery), External Calendar Subscriptions (iCalendar feed overlay), and Google Calendar (Pro feature). Each service entry now lists what it is, when data is sent, what data is sent, and links to the service's terms of use and privacy policy. Previously the section claimed the free version made no external connections, which was inaccurate — Brevo/Postmark/external calendars are all opt-in features available in the free version. - Fixed: Updated the
Contributorsline inreadme.txtfromjennydoughertytofreelancestudioltdcoto match the WordPress.org account that hosts the plugin.
Version 9.0.1
1 change
▼
- Fixed: Removed the
Author URIline from the plugin header. The WordPress.org Plugin Directory submission process flagged thatPlugin URIandAuthor URIcannot point to the same address. Sincehttps://freelancestud.iois the plugin's product page, kept it as the Plugin URI and dropped the duplicate Author URI. The author name remains in the header.
Version 9.0.0
14 changes
▼
- Slug change for WordPress.org: The plugin's WordPress.org slug is now
designosaurus-freelance-studioto comply with WP.org slug distinctiveness guidelines. The display name in the Plugin Header, the WordPress admin, the Plugins list, the WP.org listing page, and all Freemius user-facing notices remains Freelance Studio — no user-facing brand change. InternalFS_constants, class names, database tables, and admin URL slugs are unchanged. The text domain was updated todesignosaurus-freelance-studioto match the slug as required by WP.org. - Fixed: The
@fs_premium_onlydirective in the plugin header was formatted as a multi-line block, which prevented Freemius's PHP preprocessor from parsing it during deployment. As a result, premium-only files were not being stripped from the generated free version. Reformatted to the single-line comma-separated format required by Freemius so the free build correctly excludes premium code. - Fixed: Added defensive
class_exists()guards throughout the plugin so the Freemius-generated free build activates and runs cleanly without any premium classes loaded. Affected: bootstrap loader (form model/controller loading, Google Calendar Service init, cron tasks for recurring invoices/quarterly tax/weekly digest), AJAX handlers for form operations, public form renderer, dashboard financial summary, calendar controller and view, settings controller and view (tax rates fallback, templates tab, email templates tab), finances controller's tax tab, and reporting controller's tax data getter. - Security: Applied WordPress.org Plugin Directory compliance hardening across the codebase. All
json_encode()calls converted towp_json_encode()for WordPress-consistent JSON output (40 spots). All$_SERVERreads that use the value (REQUEST_METHOD, HTTP_HOST, HTTP_USER_AGENT, HTTP_CF_CONNECTING_IP, HTTP_X_FORWARDED_FOR, HTTP_X_REAL_IP, HTTP_CLIENT_IP, REMOTE_ADDR) now wrapped insanitize_text_field( wp_unslash( ... ) )(34 spots). Allwp_verify_nonce()calls now sanitize the nonce value withsanitize_text_field( wp_unslash( ... ) )before verification, with?? ''fallbacks to prevent undefined-index warnings (59 spots). - Changed: Chart.js (4.4.1) is now bundled locally in
admin/js/vendor/and enqueued on the Finances/Reporting and Client detail pages viawp_enqueue_script(), replacing the previous remote script tag loaded from jsDelivr CDN. The reporting view and client earnings chart now rely on a sharedfs-chartjshandle. Also normalizes a version mismatch where the client view was using 4.4.0 while reporting used 4.4.1. - Changed: jQuery UI base theme CSS (1.13.2) is now bundled locally in
admin/css/vendor/along with its six datepicker icon sprites, replacing the previous remote stylesheet loaded fromcode.jquery.com. Required for WordPress.org Plugin Directory compliance, which does not permit enqueuing resources from third-party CDNs. - Changed: The bug-report screenshot upload handler and expense-receipt upload handler both now use
wp_handle_upload()with anupload_dirfilter to route files into their custom subdirectories (uploads/fs-bug-reports/anduploads/freelance-studio-receipts/YYYY/MM/) instead of callingmove_uploaded_file()directly. Required for WordPress.org Plugin Directory compliance. Multi-file$_FILESarrays are now reshaped into the single-file formwp_handle_upload()expects before each file is processed. - Changed: PDF downloads for invoices, proposals, and contracts are now available on every plan, including free. Previously the admin-side download button showed a "Pro feature" alert while the public client portal exposed working downloads to anyone with the share link — the gating was inconsistent and easily bypassed. Removed the Pro restriction from both the view buttons and the controller-side redirect so the experience matches across admin, public portal, and direct PDF URLs. The unused
pdf_downloadfeature-gate definition infreelance-studio.phpwas also removed. - Fixed: The Settings page's Save Settings button was missing on the Business, Documents, Invoices, and Time tabs. An unclosed HTML comment (
<!-- ============================================with no matching-->) on the section divider line was being terminated by the next-->further down the file, which swallowed the form's submit button and closing tag inside browser-side comment text. The button rendered server-side but was invisible to users. Closed the comment with a proper section header so the Save Settings button reappears on all four tabs. - Fixed: The Invoice Wizard was returning "No active projects found" even when active projects existed for the user. The wizard's project query filtered by status values
running,upcoming, andactive— but onlyactiveis a valid project status in this codebase (alongsidepending,on_hold,completed,cancelled). Updated to filter bypendingandactive(the two in-progress states) using the canonicalFS_Project::STATUS_*constants. Also fixed the same stale status filter on the public client portal dashboard. - Changed: Free plan limits raised to match the configuration on Freemius: clients raised from 3 to 5, invoice sends per month raised from 3 to 5, active proposals raised from 1 to 5, active contracts raised from 1 to 5. Active projects per client remains at 1. Refactored all hardcoded number references in upgrade-notice strings (8 spots across the main plugin file and the clients/proposals/contracts list views) to read dynamically from
fs_studio_free_limits()so the displayed numbers always match the actual gate values. Notice strings now use WordPress's_n()helper for proper plural/singular forms when limits are 1 vs many. - Changed: The Freemius affiliate program admin page is now themed to match the Freelance Studio brand. Card-style container with a soft shadow, the program-summary list uses teal checkmarks instead of default WordPress bullets, headings have a teal accent underline, the apply/submit button uses the brand teal gradient, and form inputs match the styling used elsewhere in the plugin. CSS-only — all of Freemius's content (intro paragraphs, program summary, application form, status notices) remains intact and unchanged. Scoped under
#fs_affiliation_content_wrapperso it cannot affect other admin pages. Includes high-contrast mode overrides. - Fixed: Removed a stray closing brace in
admin/css/freelance-studio.cssthat was silently breaking CSS rules below it in the file. The orphan}between#fs-quick-task-form button[type="submit"]:hoverand.fs-task-listwas causing an unknown number of subsequent style rules to be ignored by browsers. Brace count is now balanced across the entire stylesheet. - Changed: The standalone popup timer view (
includes/views/time-tracking/popup-timer.php) is now Pro-only. Added to the@fs_premium_onlydirective so Freemius strips it from the WordPress.org free build entirely. The popup timer was already gated as a Pro feature server-side viafs_studio_is_free_plan()checks, but the view file itself was still shipping in the free ZIP. Hardened the popup handler inFS_Admin::handle_popup_timer()to also checkfile_exists()before including the view, so the handler degrades gracefully to an upgrade message regardless of whether the gating check or the file-stripping is what excludes it. Side benefit: removes the standalonedocument and its remaining inlineandtags from the WordPress.org free build, addressing the only spot where the plugin loaded WordPress core assets viarather thanwp_enqueue_script().
Version 8.8.0
6 changes
▼
- New: Project Documents Tab — Projects now have a "Documents" tab showing all linked proposals, contracts, and recurring invoices with status badges, amounts, and direct links. Includes quick-create buttons for new contracts, proposals, and recurring invoices that pre-fill the project and client. A tab indicator dot appears when documents are linked.
- New: Recurring Invoice Send-To Contacts — When "Auto-send invoice when generated" is checked on a recurring invoice, a new "Send invoices to" section appears showing checkboxes for each client contact. Selected contacts are saved and used when the cron auto-generates and sends invoices. Contacts reload via AJAX when the client changes.
- New: Set Up Recurring Invoice from Project — The project billing schedule section now shows a "Set Up Recurring Invoice" button when billing frequency is set to anything other than "once". If a recurring invoice already exists for the project, it shows the linked recurring invoice name with status badge instead.
- New: Link Contracts and Proposals to Projects — Contracts and proposals now save their
project_idwhen created from a project's Documents tab. The proposals table gains aproject_idcolumn (migration added for existing installs). Both contract and proposalget_all()methods now supportproject_idfiltering. - Fixed: Project dropdown was empty when selecting a client in the recurring invoice form. The
get_for_dropdown()method only showedpendingandactiveprojects — now also includeson_holdprojects. - Fixed: Popup timer pause/discard button icons had a white background square behind them. Removed
background-color: #ffffrom.popup-btn .dashicons.
Version 8.7.0
7 changes
▼
- New: Realized Deductions — Annual estimated deductions can now be marked as "Realized" when the actual expense has been logged. This prevents double-counting on the tax report. Each deduction in the Tax page now shows an Estimated or Realized status badge. Clicking "Realize" opens a modal where you can optionally link the deduction to a specific tracked expense for reference. Realized deductions appear dimmed with a strikethrough amount and can be undone at any time.
- New: Merged Tax Report — The Tax Deduction Summary export (PDF and CSV) now produces a single consolidated table of deductions grouped by category, merging tracked expenses and unrealized estimated deductions together. Realized deductions are excluded automatically. Each row shows whether the amount came from tracked expenses, estimates, or both. This gives your CPA one clean list of deductible categories instead of two separate sections that could overlap.
- New: Expense Search — Search expenses by name, category, notes, or project name. The search input appears in the expense filter bar and works alongside existing category and date filters. A "Clear" link appears when any filters are active.
- Improved: Sidebar navigation in Finances, Settings, and Bookings collapses to icon-only mode on medium-width screens (783px–1200px), freeing ~150px for content.
- Fixed: Expense, invoice, income, and reporting filter forms submitted to old page slugs (
fs-expenses,fs-invoices,fs-reporting) causing "Sorry, you are not allowed to access this page" errors. All now correctly submit tofs-financeswith the appropriate tab. - Fixed: Tax Deduction Summary PDF rendered tables as unformatted text. Added table support to
FS_PDF::WriteHTML()with header rows, borders, alignment, and subtotal styling. - Fixed: Tax PDF title showed raw
{{H1}}markers.WriteHTML()now strips/blocks before processing content.
Version 8.6.0
6 changes
▼
- New: Email Delivery Settings — Built-in integration with Brevo and Postmark transactional email APIs. Ensures invoices, proposals, contracts, booking confirmations, and all other emails reliably reach clients' inboxes instead of landing in spam.
- New: Setup Wizard — Step-by-step wizard in Settings → Email Delivery walks users through choosing a provider, creating an account, entering their API key, verifying the connection, and sending a test email. Supports three paths: Brevo (free 300 emails/day), Postmark (fastest delivery), or "I already use an SMTP plugin."
- New: Email Delivery Service (
class-fs-email-delivery.php) — Hooks into WordPress'spre_wp_mailfilter to route all emails through the configured provider's API. Includes full header parsing (From, Reply-To, CC, Content-Type), automatic fallback to defaultwp_mail()if the API call fails, and error logging. - New: API Key Verification — Verify Connection button tests the API key against the provider's account endpoint before saving, preventing misconfiguration.
- New: Test Email — Send a branded test email from both the setup wizard and the configured status view to confirm end-to-end delivery.
- Improved: Email Templates settings tip now links to the new Email Delivery settings instead of generically suggesting an SMTP plugin.
Version 8.4.0
3 changes
▼
New Features
- Finances Hub: New unified "Finances" menu in the WordPress sidebar, consolidating all financial features into one location with sidebar navigation (same pattern as Bookings and Settings).
- Backward Compatibility: Old bookmarked URLs (
?page=fs-invoices,?page=fs-expenses,?page=fs-recurring-invoices,?page=fs-reporting) automatically redirect to the correct Finances sub-page with all query parameters preserved. - WordPress admin sidebar reduced from 14 items to 11 for a cleaner navigation experience.
Version 8.3.3
1 change
▼
- Added: Expense CSV Import — the Settings > Import tool now supports importing expenses in addition to invoices. A type selector at the top lets you choose between "Invoices" and "Expenses" before uploading. Expense import auto-maps columns for Date, Amount, Merchant, Category, Description/Purpose, Notes, and Sales Tax. Expense names are built from Merchant + Purpose (e.g., "Adobe Creative Cloud — Software"). Preview shows expense count, total amount, and a full preview table before committing. Batched processing with progress bar, same as invoice import.
Version 8.3.2
1 change
▼
- Added: Pagination on the Invoices list page. Defaults to 25 per page with options for 10, 25, 50, or 100. Shows "Showing X–Y of Z invoices" info, page number links with ellipsis for large page counts, and prev/next navigation. Filters (status, client) are preserved across pages. Per-page preference is carried in the URL.
Version 8.3.0
3 changes
▼
- Added: CSV Import Tool in Settings > Import. Upload a CSV file containing historical invoice data (from Wave, FreshBooks, QuickBooks, or any other tool) and import clients, projects, and invoices into Freelance Studio. Features include:
- Added: Client Merge — reassign all projects, invoices, proposals, contracts, expenses, tasks, bookings, and contacts from one client to another, then delete the source client. Available via "Merge Into..." in the client card/row action menus. Includes a preview step showing exactly how many records will be reassigned before confirming.
- Added: Client Archive — archive and restore clients from the card/row action menus. Archived clients move to the existing "Archived" tab and are excluded from active views and dropdowns.
Version 8.1
1 change
▼
- Changed: Weekly digest email header now uses the teal-to-lime gradient (
--fs-teal-lime) with dark text (--fs-gray-800) instead of teal-to-purple with white text. Applied to both the real email and the settings preview/test email.
Version 7.10.0
6 changes
▼
- New: Preset Service Templates are now available on Proposal and Contract forms (previously only on Projects). Select "Load Preset Service" to populate services from your saved templates.
- Fixed: Proposal and Contract email templates no longer show escaped backslash in apostrophes (e.g.,
don\'t→don't). Also fixed the template save method to prevent future occurrences by properly unslashing POST data. - Fixed: Proposal Viewed notification email now correctly shows the client name (uses
get_display_nameinstead of deprecatednamefield), the correct proposal total (total_amountfield), and the timestamp in the site's local timezone instead of UTC. Same fixes applied to Contract Viewed and Invoice Viewed notifications. - Fixed: Send email modal now truncates long client contact names so the email address is always visible, making it easier to identify the correct recipient.
- Fixed: Proposal revision requests from the client public view now work correctly. The form was missing an AJAX submission handler and had incorrect nonce/field names, so submissions would silently fail. Now properly sends the revision request, stores the notes, updates status to "Revision Requested," sends notification email to freelancer, and displays the revision notes on the admin Proposal view.
- Improved:
addPresetServiceJS function now handles both.fs-service-name-input(project form) and.fs-service-name(proposal/contract form) class names when filling in preset service data.
Version 7.9.0
6 changes
▼
- New: Capped Hours for Hourly Projects — When a service is set to "Hourly > From tracked time," you can now enable "Cap my hours" to set a time budget. This shows a retainer-style progress widget on the project view with Hours Budgeted / Used / Remaining and a visual progress bar.
- New: Configurable overage rate — When hours exceed the cap, overage time can be billed at a different rate (e.g., 1.5x). Defaults to the service's standard hourly rate if not set.
- New: Cap reached notifications — When tracked hours cross the cap threshold, the system emails the freelancer automatically. Optionally notify the client too (per-project toggle).
- New: Invoice auto-split — When generating an invoice from tracked time on a capped project, line items automatically split into standard hours (at regular rate) and overage hours (at overage rate) with clear labeling.
- Updated: Retainer widget partial refactored to support both retainer and capped hourly modes as a unified "time budget widget."
- Fixed: AJAX service sanitizer now properly saves retainer and hour cap fields when updating services inline.
Version 7.8.0
4 changes
▼
- New: Email sending for invoices, proposals, and contracts now sends a single email with the primary recipient in "To" and additional contacts in "CC", instead of separate emails to each contact. All recipients see the same email thread.
- New: Send modal redesigned with To/CC selection — users can choose which contact receives the email directly (To radio button) and which contacts get a copy (CC checkboxes). Primary client contact defaults to "To" with additional contacts defaulting to CC.
- New: Email personalization (e.g.,
{client_name}) now uses the selected "To" recipient's name, ensuring the greeting matches the primary recipient even when CC'd contacts have different names. - New: Added
resolve_contact_info()helper to email service for consistent contact name/email resolution across all document types.
Version 7.7.0
4 changes
▼
- New: Each time entry now shows both actual logged time and rounded billable time when time rounding is enabled. A subtle "→ 00:20:00" indicator appears below the actual duration (e.g., 00:17:03 → 00:20:00 for 5-minute rounding), making it clear how rounding affects each entry. Only displays when rounding actually changes the value and the entry is billable.
- New: Summary bar on time tracking page now shows total rounded billable hours alongside the raw billable time (e.g., "Billable: 33:37:41 / 35.52 hrs rounded (5-min)"), making it transparent where the uninvoiced dollar amount comes from.
- New: Project view timer tab also shows rounded hours in the billable stat and per-entry rounded durations.
- New: Summary SQL now returns
rounded_billable_hoursandrounded_uninvoiced_hoursfor display in summary bars.
Version 7.5.0
6 changes
▼
- Added: Recurring Tasks tab on Tasks list page — view, edit, and delete recurring task templates from a central location
- Added: Mobile card view for Recurring Invoices list — matching the Invoices mobile design with name, client, frequency, amount, and next invoice date
- Added: Mobile card view for Invoices list — two-column layout with client name, invoice number, status badge, amount, and due date
- Added: Overdue invoice auto-detection — invoices with status sent/viewed/partial that are past due automatically update to "overdue" status when viewing the invoices page
- Improved: Past-due invoice dates display in danger red on mobile, checking actual due date rather than just status field
- Improved: Invoice mobile dates use compact MM/DD/YY format
Version 7.4.0 – 7.4.3
7 changes
▼
- Added: Mobile card view for Projects list — cards with client logo, project name, status badge, and invoiced amount (matching Clients card design)
- Added: Mobile card view for Proposals list
- Added: Mobile card view for Contracts list
- Added: Active/Archived tabs for Clients list page (replaced All/Active/Inactive dropdown)
- Improved:
matchMediaused for mobile detection in tab dropdown JS (works with browser DevTools responsive mode) - Fixed: Card dropdown menus no longer clipped by cards below (z-index management)
- Fixed:
.fs-mobile-onlybreakpoint corrected from 600px to 782px
Version 7.2.0
2 changes
▼
- Improved: "Report a Bug" button collapses to just the bug icon on mobile screens, tucked against the left edge to save space
- Fixed: "Report a Bug" button repositioned to bottom-left to avoid overlapping with the floating timer indicator
Version 7.1.0
8 changes
▼
- Security: Removed TCPDF library (v6.7.5) which had multiple disclosed CVEs (LFI, ReDoS, XSS, hash comparison bypass)
- Changed: Replaced TCPDF with new built-in FS_PDF library for all PDF generation (invoices, proposals, contracts, income reports)
- Changed: PDF output is now clean PDF 1.4 with no /OpenAction, /JS, or /AcroForm directives — prevents Gmail virus scanner false positives
- Changed: Signature images in contract PDFs now rendered via temp file conversion instead of inline base64
- Changed: UTF-8 text (smart quotes, emoji, special characters) properly converted to WinAnsi for PDF compatibility
- Changed: Contract terms HTML rendered via lightweight HTML parser (supports headings, bold, italic, lists, paragraphs, horizontal rules)
- Improved: Plugin size reduced ~1.5MB by removing bundled TCPDF library and font files
- Improved: WordPress output buffer handling hardened — clears all nested buffer levels before PDF output to prevent corruption
Version 7.0.0
14 changes
▼
- Major: Freemius SDK integration for freemium distribution model.
- Architecture: Renamed all
FS_plugin constants toJEEB_FS_(FS_VERSION → JEEB_FS_VERSION, FS_PLUGIN_DIR → JEEB_FS_PLUGIN_DIR, etc.) to prevent namespace conflicts with Freemius SDK's ownFS_constants. - Architecture: Added
@fs_premium_onlyfile exclusion list to plugin header for automatic free version generation. Files for booking, Google Calendar, project templates, milestones, file uploads, recurring invoices, tax tools, email templates, and the premium helper directory will be stripped from the free version. - Architecture: Conditional file loading in
load_dependencies()— premium-only models, controllers, and services now usefile_exists()checks so the free version doesn't fatal error when stripped files are missing. - Feature: Freemius SDK initialization with
fs_studio()helper function, 14-day free trial support, and Pro plan configuration. - Feature: Complete premium gating helper system —
fs_studio_is_free_plan(),fs_studio_can_use_premium(),fs_studio_limit_reached(),fs_studio_get_usage_count(),fs_studio_increment_invoice_sends(),fs_studio_upgrade_notice(), andfs_studio_show_powered_badge(). - Feature: Free plan limit configuration — 3 clients, 1 active project per client, 3 invoice sends/month, 1 active proposal, 1 active contract.
- Feature: Upgrade notice rendering system with four display contexts (inline, banner, modal, tooltip) and centralized message registry for all gated features.
- UI: Complete upgrade notice CSS — PRO badges, inline notices, banner notices, locked button states, limit warning banners, and "Powered by Freelance Studio" badge styling.
- UI: High-contrast overrides for all upgrade notice components.
- Architecture: Created
/includes/premium/directory for future premium-only helper classes. - Architecture: Created
/vendor/freemius/with development stub SDK that grants full access during local development. Must be replaced with real Freemius SDK before deployment. - Architecture: Updated
uninstall.phpto integrate with Freemius after_uninstall hook for proper cleanup with user feedback collection. - Note: This version establishes the Freemius foundation. Phase 2 (hard gates on individual features) and Phase 3 (usage limit enforcement in controllers/views) are next.
Version 6.7.0
9 changes
▼
- Feature: Solid or gradient option for header color. Users can now choose between a solid color or a two-color gradient for document headers.
- Feature: Gradient direction picker with 8 directional presets (↑ ↗ → ↘ ↓ ↙ ← ↖) for controlling gradient angle.
- Feature: Live color swatch preview showing the current solid/gradient result.
- Feature: Solid/Gradient segmented toggle with animated active state, replacing the single color picker.
- Enhancement: Header preview in settings now reflects gradient in real-time as colors and direction change.
- Enhancement: Light logo thumbnail background also updates with gradient when in gradient mode.
- Architecture: New
--primary-bgCSS variable in document styles — backgrounds use gradient/solid, while text colors and borders remain solid via--primary-color. - Backend: Added
fs_invoice_primary_color_mode,fs_invoice_primary_color_2, andfs_invoice_gradient_directionoptions across activator, admin save handler, AJAX auto-save, settings export/import, and all controllers. - Applies to: Public invoice, proposal, and contract headers + admin preview headers. Portal, booking, email, and PDF accents remain solid color.
Version 6.6.0
3 changes
▼
- Improvement: Added
margin-top: 15pxto the button header area on the Project > Timer tab so the action buttons aren't flush against the timer/quickadd widgets above. - Feature: Custom activity types now display with color-coded badges on time entry lists, matching the styling of default activities (Development, Design, Meeting, etc.). Colors are assigned deterministically from the FS palette using a hash of the activity name, so they remain consistent. Applies to Time Tracking list, Project timer tab, and Client time entries tab. High-contrast mode is automatically covered by existing
.fs-activity-badgeoverride. - Feature: Time entries list (Timer View) is now paginated at 25 entries per page. Shows "Showing X–Y of Z entries" info, page number links, and prev/next navigation. All active filters are preserved across pagination. Added
count_all()method toFS_Time_Entrymodel.
Version 6.5.0
3 changes
▼
- Bug Fix: Fixed WordPress
wpdbNULL handling across all models —wpdb->update()andwpdb->insert()convert PHPnullto empty strings, which MySQL casts to0for bigint columns instead of SQLNULL. This affected nullable foreign key fields (project_id, contract_id, proposal_id, task_id, invoice_id, milestone_id, parent_task_id, client_id, etc.) across the entire plugin, preventing users from clearing/removing assignments. - New: Added
FS_DB_Helperutility class withfix_null_fields()method to properly handle NULL values after wpdb operations, used consistently across all models. - Models Fixed: Invoice, Contract, Project, Task, Expense, Recurring Invoice, Time Entry, Milestone, Retainer Period, Form, Form Response
Version 6.4.0
3 changes
▼
- Improvement: Dashboard task widget status pills are now inline editable dropdowns — change task status directly from the dashboard without navigating away
- Improvement: Dashboard status dropdowns match the original pill size and shape (11px, 3px/10px padding, 20px border-radius) so they look identical to the previous static badges
- Improvement: Selecting "Done" from the dashboard dropdown animates the task out, same as checking the completion checkbox
Version 6.3.0 — Brand Consistency Pass
10 changes
▼
- Improvement: Projects page — added "Projects" page title, moved "New project" button to top right
- Improvement: Proposals page — added "Proposals" page title, moved "New proposal" button to top right
- Improvement: Contracts page — added "Contracts" page title, moved "New contract" button to top right
- Improvement: Clients page — moved view toggle (grid/list) next to "Clients" title, "New client" button stays top right
- Improvement: Bookings page — removed icon from title, replaced horizontal WordPress nav tabs with vertical sidebar tabs matching Settings page layout (
fs-settings-layout/fs-settings-sidebar) - Improvement: Calendar page — removed icon from title, styled as
fs-page-title - Improvement: Forms page — restyled buttons from WordPress
.button/.button-primaryto FS.fs-btn-secondary/.fs-btn-primary, consistent with all other pages - Improvement: Reporting — Income Summary (PDF) button changed from primary to secondary
- Improvement: Expenses — Export for Tax Preparer button restyled from WordPress
.buttonto.fs-btn-secondary - Bug Fix: Removed 📅 emoji from Bookings upcoming widget, replaced with dashicon
Version 6.2.0
1 change
▼
- New Feature: High Contrast Mode — a toggle in Settings > Business > Accessibility that transforms the entire plugin UI to meet WCAG AAA contrast standards (7:1 ratio):
Version 6.1.0
3 changes
▼
- New Feature: Quick timer button on dashboard task list — each task now shows a clock icon on hover that opens a popup timer pre-populated with the task and project; only appears on tasks that have a project assigned
- New Feature: Timer task dropdown now filters by selected project — when a project is selected in the timer widget (on both the dashboard and time tracking page), the task dropdown automatically hides tasks from other projects, showing only relevant tasks; reverts to showing all tasks when no project is selected
- New Feature: Recurring invoices can now auto-populate with unbilled time entries — new "Billable Time" section on the recurring invoice form with options to:
Version 6.0.0
2 changes
▼
- New Feature: Task Archiving — archive completed tasks to declutter your Kanban board and task list while preserving them for reference
- Database: Added
previous_statuscolumn to tasks table with automatic migration
Version 5.9.0
4 changes
▼
- Bug Fix: Kanban columns now stretch to fill the full board height instead of sizing to their content — columns with fewer cards fill the same vertical space as columns with many
- Bug Fix: Individual column bodies scroll vertically when cards overflow, instead of the entire board scrolling — changed board from
align-items: flex-starttostretchand addedoverflow-y: hiddenon board - Bug Fix: Removed
max-heightfrom columns; height is now properly constrained by the flex container chain (wrap → board → column → body) - Bug Fix: Column headers no longer shrink when column body has many cards (
flex-shrink: 0)
Version 5.8.0
5 changes
▼
- New Feature: Weekly/biweekly recurring tasks now support day-of-week selection
- Added day picker UI (M/T/W/T/F/S/S chips) to the recurring task options — shown when frequency is Weekly or Every 2 Weeks
- Tasks recur on the next matching selected day rather than a fixed 7/14-day interval
- New
recurring_daysdatabase column (auto-migrated on activation) - Recurring days carried forward to all future recurring instances
Version 5.7.0
7 changes
▼
- New Feature: Popup timer for tasks — click the play button on any task row to launch a small desktop timer window
- Timer popup pre-fills task name, project, and activity; includes start/stop/pause/resume/discard controls
- Timer window title updates with elapsed time for easy tracking from the taskbar
- Auto-closes with confirmation after stopping and saving
- Warns if another timer is already running
- Added to all task views: Tasks list, Kanban board, Project tasks tab, and Client tasks tab
- Timer button only shows on incomplete tasks
Version 5.5.0
1 change
▼
Fixed
- Client Card View Delete: Fixed delete not working in card view. The card view was using a direct URL link (
action=delete) but the clients controller had nodeletecase — it fell through todefaultwhich just re-rendered the list. Changed to use the same AJAX-basedfs-delete-btnpattern that the list view uses, which calls the existingdelete_clientAJAX handler.
Version 5.4.0
2 changes
▼
Added
- Recurring Tasks: Tasks can now be set to automatically reappear on a schedule
- Database: Added
is_recurring,recurring_frequency,recurring_end_date, andparent_task_idcolumns to tasks table with automatic migration for existing installs
Version 5.3.0
9 changes
▼
Added
- Client Task Requests: Clients can now request tasks directly from the client portal — both from the project Tasks tab and a new Tasks section on the portal dashboard
- Portal Dashboard Tasks Section: New Tasks section on the portal dashboard displays all client-visible tasks across all active projects, with status labels, priority indicators, due dates, and a collapsible completed tasks section
- Task Request Modal: Clean modal interface for clients to submit task requests with title, description, priority, due date, and project selection
- "Requested" Task Status: New
requestedstatus for tasks submitted by clients — these appear in the Pending column on the admin kanban board with a distinctive pink "Request" badge - Accept Task Request Flow: Kanban cards with requested status show an Accept button (green checkmark) — clicking it changes the status to Pending and notifies the client
- Task Request Email Notifications: When a client submits a request, an email is sent to the freelancer with full task details and a link to the Tasks board; when the freelancer accepts, a confirmation email is sent to the client with a link to their portal
- Success Toast Notifications: Client portal now shows a brief success toast when a task request is submitted
Improved
- Kanban Board: Requested tasks are included in the kanban query and mapped into the Pending column for easy visibility
- Task Model: Added
get_client_visible_tasks()method for efficiently fetching all client-visible tasks across projects
Version 5.2.0
16 changes
▼
Bug Fixes
- Fixed issue where cancelled bookings kept reappearing on Google Calendar
- Root cause: When a booking was cancelled, the event was deleted from Google, but subsequent sync operations would recreate it
- Three-part fix implemented:
- Fixed critical bug where contractor signature was not displaying on proposals and contracts
- Root cause:
esc_url()was stripping base64 data URIs (thedata:protocol is not in WordPress's allowed protocols list) - Changed to
esc_attr()for signature image src attributes in all 4 views: - Fixed "wp.media is not a function" error when uploading business logo in Settings
- Added
wp_enqueue_media()call for the settings page to load WordPress media library scripts - Restructured JavaScript to use event delegation for signature-related buttons
- Tab switching, file upload, and remove button now work regardless of canvas state
- File upload handlers no longer require canvas to be present
- Added
contractor_signature,contractor_signer_name, andcontractor_signer_titleto frontend router'sget_business_settings()method - Signatures now properly display on client-facing views
Previous Fixes (5.1.14-5.1.18)
- PHP Warning fix for undefined
is_defaultproperty in contract sections - CSS color variable updates for document preview title
- Payment Reminders card relocated to invoice sidebar
Version 5.1.0
14 changes
▼
Improvements
- Dynamic File List: Uploaded files now appear instantly in the list without page refresh
- Longer Success Message: Success notification now stays visible for 8 seconds
- Highlight Animation: Newly uploaded files are highlighted with a subtle green animation
- HTML Formatting: Email notifications now match the plugin's styled HTML email template
- Brand Colors: Uses your configured brand color for consistency
- Direct Link: Includes a button to view the project files directly
- New Files Tab: Files section moved from sidebar to dedicated "Files" tab
- Card Grid Layout: Files displayed in a responsive grid of cards instead of a list
- Improved Upload Area: Larger, more prominent drag-and-drop zone
- Better Organization: Clear separation between shared files and upload section
- Improved Empty State: Contracts list now shows a friendly empty state with icon when no contracts exist, matching the proposals page design
- Improved Headers: Admin notification emails now use proper From headers for better deliverability with Gmail and other providers
Bug Fixes
- Fixed undefined property warnings in file enrichment when attachment is missing
- Fixed portal files not displaying all shared files (was filtering files without URLs)
Version 5.0.0
4 changes
▼
New Features
- Consolidated Tools Tab: All repair and diagnostic tools now live in one place under Settings → Tools
Improvements
- Moved "Repair URLs" button from Booking Settings to the centralized Tools tab
- Added fallback form submission for Repair URLs when JavaScript is disabled
- Updated booking settings to reference the new Tools tab location for URL repair
Version 3.10
9 changes
▼
New Features
- Client-Level Tasks: Tasks can now be created directly under a client without requiring a project. This is useful for ongoing client relationship tasks (follow-ups, check-ins, general consulting).
- Internal Tasks Dashboard Widget: When Internal Project Tracking is enabled, a new "Internal Tasks" widget appears on the dashboard showing pending tasks for your internal client.
- Enhanced Task Model: Tasks now support
client_idfield for direct client association independent of projects.
Improvements
- Task list view now shows client name below project name for better context
- Client tasks display with "Client Task" indicator to distinguish from project tasks
- Internal tasks display with "Internal" badge for quick identification
- Renamed "Generic" task labels to "Internal" throughout the UI for clearer terminology
- New
get_by_client()andget_internal_tasks()helper methods in Task model
Bug Fixes
- Fixed SQL ambiguity error in
count_by_client()method wherestatuscolumn was not prefixed with table alias
Version 3.9.0
11 changes
▼
Major Feature: Retainer as Service Pricing Type
Changes
- Retainer Service Pricing: Added "Monthly Retainer" as a pricing type option for services
- Removed Project-Level Retainer Section: The separate "This is a retainer project" checkbox in the Billing section has been removed
- Reusable Retainer Widget: Created
includes/views/partials/retainer-widget.php - Helper Methods: Added new methods to
FS_Projectmodel
UI/UX
- Retainer service fields appear inline with other pricing options
- Clean teal background with organized layout
- Responsive grid layout for retainer fields
- Checkbox for rollover setting directly visible
Backwards Compatibility
- Legacy
is_retainer,retainer_amount,retainer_hours, andretainer_rolloverfields are automatically populated from service data when saving - Existing retainer projects using old approach will continue to work
FS_Project::is_retainer_project()checks both new service-based and legacy approaches
Version 3.8.0
10 changes
▼
New Features
- 1099 Year-End Report: Generate a professional PDF summary of all clients paid $600 or more during the tax year
- Duplicate Project: One-click copy a project with all its tasks and milestones
- Batch Mark Invoices Paid: Select multiple invoices and mark them as paid at once
- Export to CSV: Export your data for use in spreadsheets or other software
- Retainer Tracking System: Comprehensive retainer/subscription management
UI Improvements
- Added "Export CSV" button to Invoices list page
- New "Export & Reports" section on Reporting page with quick-access buttons
- Batch actions bar for invoice list with count display
- Retainer summary widget with progress visualization
Database Changes
- New
fs_retainer_periodstable for tracking retainer usage and rollover
Version 3.7.0
12 changes
▼
New Features
- Invoice Wizard Button on Time Tracking Page: Added a prominent "Invoice Wizard" button to the Time Tracking page for quick access to create invoices from tracked time
- Interactive Reporting Charts:
Improvements
- Activity Name Capitalization: Activity names are now properly capitalized (first letter uppercase) throughout the Invoice Wizard preview and final invoices
- Updated Color Styling:
Bug Fixes
- Project Deletion Fixed: Projects can now be properly deleted after their invoices have been removed
- Dashboard Task Completion Fixed: Marking a task as complete from the dashboard now persists correctly
Technical Details
- Added Invoice Wizard modal include and button handler to Time Tracking list view
- Updated
groupTimeEntries()JavaScript function to capitalize activities - Updated
build_time_entry_items()PHP method to useucfirst()on activity names - Added Chart.js integration for reporting page visualizations
- Added
.fs-text-accentCSS utility class - Added chart container and interactive legend CSS styles
Version 3.6.0
8 changes
▼
Improvements
- Invoice Wizard Time Entry Grouping: When using "Individual Entry" grouping, invoice line items now show both the activity type AND the description (e.g., "01/05 - Development - Circle landing page" instead of just "01/05 - Circle landing page")
Bug Fixes
- Fixed: "Headers Already Sent" Error: Comprehensive fix for redirect issues that caused blank pages after saving settings, clients, projects, etc. Added early output buffering via
admin_inithook to capture PHP 8.1+ deprecation warnings before redirects - Fixed: PHP 8.1+ Deprecation Warnings: Added null checks to
str_replace()andstrpos()calls in email templates and email service to prevent deprecation warnings that were breaking redirects
Grouping Options Reference
- Activity Type: Groups all entries by activity, shows activity name with date range if enabled
- Task: Groups entries by task, shows task name with date range if enabled
- Individual Entry: Each time entry as a separate line item, shows activity type + description
- Project Total: Single line item summarizing all hours for the project
Contract View Updates
- Changed: "Create Invoice" button on Contract view now opens the Invoice Wizard modal instead of the old dropdown menu
Version 3.5.0
7 changes
▼
Breaking Changes
- Client Contact Architecture Overhaul: The client record no longer stores a built-in "primary contact". All contacts are now managed through the Contacts list.
Migration
- Automatic Data Migration: When upgrading to v3.5.0, the plugin automatically migrates existing primary contact data:
New Features
- Unified Contacts Management: All contacts (including the primary contact) are now managed in one place
- New Helper Methods: Added
FS_Client::get_display_name(),get_primary_contact(), andget_document_info()for consistent client info retrieval across the plugin
Improvements
- Client form reorganized with "Company Information" as the primary section
- Better visual distinction for contact type badges
- Improved contact form UX with radio buttons for primary selection
Version 3.4.0
19 changes
▼
New Features
- Invoice Wizard: New multi-step wizard for creating invoices from the Invoices list or Project view
- Multi-Project Invoices: Create a single invoice that includes items from multiple projects
- Time Entry Grouping Options:
- Service Selection: Choose exactly which services to bill - no longer forced to include all services
- Service Partial Billing: Bill a percentage or custom amount of each service individually for deposits or milestone payments
- Invoice Editing Rules:
Bug Fixes
- Orphaned Time Entries: Fixed issue where deleting an invoice left time entries marked as "invoiced", preventing them from being billed again. Invoice deletion now properly resets linked time entries to unbilled status.
- Automatic Data Repair: Plugin update automatically detects and repairs any existing orphaned time entries from previous invoice deletions
- Container ID Consistency: Fixed multiple HTML/JS container ID mismatches that prevented time entries and services from rendering in the wizard
Database Changes
- Added
invoice_sourcecolumn to invoices table to track creation method - Added
time_groupingcolumn to invoices table - Added
show_entry_datescolumn to invoices table - New
fs_invoice_itemstable for detailed line item storage - New
fs_invoice_projectsjunction table for multi-project invoices
UI Improvements
- Invoice Wizard button added to Invoices list page
- Project view Invoice button now opens the wizard
- Invoice form shows locked notice for paid invoices
- Invoice form shows resend warning for sent invoices that have been edited
- Improved wizard step 2 styling with clear section headers and checkbox lists
Version 3.2.0
14 changes
▼
New Features
- Invoice Wizard: New multi-step wizard for creating invoices from the Invoices list or Project view
- Multi-Project Invoices: Create a single invoice that includes items from multiple projects
- Time Entry Grouping Options:
- Service Partial Billing: Bill a percentage or custom amount of a service for deposits or milestone payments
- Invoice Editing Rules:
Database Changes
- Added
invoice_sourcecolumn to invoices table to track creation method - Added
time_groupingcolumn to invoices table - Added
show_entry_datescolumn to invoices table - New
fs_invoice_itemstable for detailed line item storage - New
fs_invoice_projectsjunction table for multi-project invoices
UI Improvements
- Invoice Wizard button added to Invoices list page
- Project view Invoice button now opens the wizard
- Invoice form shows locked notice for paid invoices
- Invoice form shows resend warning for sent invoices that have been edited
Version 3.1.0
24 changes
▼
New Features
- Added ability to set up recurring expenses for subscriptions (Adobe, hosting, etc.)
- Support for monthly, quarterly, and yearly recurring frequencies
- Option to specify the day of month for recurring charges
- Option to set an end date for recurring expenses
- Recurring expenses are displayed with a 🔄 badge in the expense list
- Monthly recurring total shown in expense summary
- Automatic generation of expense entries via daily cron job
- Added support for linking external calendars via public iCal/ICS URLs
- Compatible with Office 365, Outlook, Apple iCloud Calendar, and any iCal-compatible service
- Option to block availability for meeting booking based on external calendar events
- Automatic hourly sync of external calendars
- Manual sync option available in settings
- Setup instructions included for major calendar providers
- Added text labels to status indicators in time tracking list (Invoiced, Billable, Non-billable)
- Colored status badges for better visibility and intuitive understanding
- Improved accessibility over color-only indicators
Bug Fixes
- Fixed issue where tasks were not showing in the admin dashboard
- Changed query from invalid 'incomplete' status to valid ['pending', 'in_progress'] statuses
- Tasks now properly display in the dashboard Tasks widget
Technical Changes
- Added new database columns for recurring expenses (is_recurring, recurring_frequency, recurring_day, recurring_end_date, parent_expense_id)
- Added new database table for external calendars (fs_external_calendars)
- Added cron job for recurring expense generation (daily)
- Added cron job for external calendar sync (hourly)
- Database version updated to 3.1.0
Version 3.0.0
13 changes
▼
Added
- Invoice Project Modal - New modal interface when creating invoices from projects
- Project Name on Invoices - Project name now prominently displayed on all invoice views
- SEO Protection for All Public Pages - Added
noindex, nofollowmeta tags to all client-facing pages
Changed
- Simplified Hourly Rate Architecture - Removed redundant "Default Hourly Rate" field from projects
- Invoice Creation from Projects - Completely redesigned workflow
- Invoice Email Subject - Now includes project name: "Invoice #X for Project Name from Business"
Fixed
- Invoice line items not displaying on public invoice view (field name mismatch)
- Time tracking calculations now correctly use project service rates
- Quick Add form pre-fills correct hourly rate from project services
- Timer widget applies correct rate when starting timer on project
Security
- All public-facing pages now include
noindex, nofollowmeta tags - Token-based access verified for all client portal and document views
- Links are only accessible to those with the direct URL
Version 2.14.0
6 changes
▼
Changed
- Simplified Hourly Rate Management - Removed redundant "Default Hourly Rate" field from projects
Removed
- Project Default Hourly Rate Field - No longer needed as services define the rates
Fixed
- Time tracking stats (Billable Amount, Uninvoiced) now correctly use the project's service rate
- Quick Add form correctly pre-fills rate based on project's hourly service
- Timer widget correctly applies project service rate when starting timer
- Invoice creation from project uses correct hourly rate from services
Version 2.13.0
1 change
▼
Added
- Contract Sections Library - Reusable legal sections for contracts
Version 2.12.0
1 change
▼
Added
- Recurring Invoices - Automatically generate invoices on a schedule
Version 2.11.0
1 change
▼
Added
- Payment Reminders - Automated email reminders for unpaid invoices
Version 2.10.0
1 change
▼
Added
- Project Templates - Save and reuse project configurations
Version 2.9.0
1 change
▼
Added
- Time Tracking Reports - Detailed time analysis
Version 2.8.0
1 change
▼
Added
- Task Management - Track project tasks and to-dos
Version 2.7.0
1 change
▼
Added
- Milestones - Track project progress with milestones
Version 2.6.0
1 change
▼
Added
- Google Calendar Integration - Sync deadlines and events
Version 2.5.0
1 change
▼
Added
- Email Templates - Customizable email templates
Version 2.4.0
1 change
▼
Added
- Annual Tax Deductions - Track yearly deductible expenses
Version 2.3.0
1 change
▼
Added
- Client Portal - Secure area for clients to view their information
Version 2.2.0
1 change
▼
Added
- Proposals - Create and send professional proposals
Version 2.1.0
1 change
▼
Added
- Contracts - Digital contract management
Version 2.0.0
1 change
▼
Added
- Time Tracking - Track billable hours
Version 1.0.0
10 changes
▼
Added
- Initial release
- Client management with multiple contacts per client
- Project management with hourly, fixed-price, and retainer billing types
- Invoice generation with line items, discounts, and tax calculations
- Expense tracking with categories and receipt uploads
- Dashboard with YTD revenue, expenses, and tax summary
- Reporting with monthly income/expense breakdown and tax estimates
- Settings page for business info, branding, and tax configuration
- PDF invoice generation
- Tax calculator with federal and state tax rate support
