Changelog

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_type column (invoice | estimate); every financial query defaults to doc_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_layout user meta gains a hidden list), 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 duplicate render_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) in FS_Google_Calendar_Service::generate_weekly_digest(), with matching sample data in get_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 an archived status 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_complete plus FS_Email_Service::send_task_completion_notification(). The shared modal partial includes/views/partials/notify-client-task-modal.php is 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.php was missing two closing tags after its , leaving #fs-contact-modal and .fs-modal-content open. The closing in view.php (intended to close .fs-tab-content and .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's displayed as AP\'s). The fs_update_project_services AJAX handler was sanitizing $_POST['services'] without first calling wp_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_date to "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 calls fs_get_client and overwrites #due_date with the client's default payment terms. Added a fsInitialClientLoad guard 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 an input[type="radio"]:checked::before white 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 ::before pseudo-element (via a higher-specificity rule, no !important needed) 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: none but had no border in their default state and no checked-state styling (the radio relied on accent-color, which has no effect once appearance: none is 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 / $_REQUEST with wp_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 in class-fs-task.php (smart-recurring filters in both list and count queries, and the recurring-parents query) by switching to $wpdb->prepare() with %s placeholders. The $today value comes from current_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.COLUMNS lookups) to $wpdb->prepare() with %s placeholders 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 both class-fs-finances-controller.php::save_quarterly_payments() and class-fs-settings-controller.php before iteration: now wraps with wp_unslash, validates is_array, forces the quarter key through intval and rejects values outside 1–4. Inner amount/date sanitization (already present) is unchanged.
  • Security: Sanitized $_POST['expenses'] array source in class-fs-invoices-controller.php with wp_unslash before iteration. Each $expense_id was already cast through intval.
  • Security: Sanitized the $_POST['signature_data'] / $_POST['signature'] raw read in class-fs-frontend-router.php::ajax_sign_proposal with wp_unslash at the entry point. Content sanitization continues through FS_Security_Service::sanitize_signature() which validates the base64 data URI format. sanitize_text_field is intentionally NOT used here because it would strip valid characters from the base64 payload.
  • Security: Sanitized the $_GET array passed to add_query_arg() in class-fs-admin.php::handle_early_redirects(). Each value is now wrapped with wp_unslash and sanitize_text_field, and the result is passed through urlencode_deep() before being merged into the redirect URL, per WP coding standards.
  • Security: Sanitized the $_GET filter inputs in kanban.php, projects/list.php, tasks/list.php, proposals/view.php, expenses/list.php, bookings/list.php, invoices/list.php, settings/index.php, and the time-tracking-controller.php::reports() and ::form() methods with wp_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; in freelance-studio.php::fs_studio_pro_upgrade_html() with echo wp_kses_post($html);, and upgraded the bare __() calls inside (Upgrade-to-Pro / Upgrade-Now CTA labels) to esc_html__(). Each piece composing the HTML is individually escaped at construction, with wp_kses_post as the safety net at the output boundary.
  • Security: Replaced echo $html; in class-fs-admin.php::export_tax_deductions_pdf() (the downloadable HTML fallback for the tax-deduction summary) with echo wp_kses_post($html);.
  • Security: Restructured the dynamic emission in class-fs-view-context.php::render_custom_activity_css() so the opener and closer are literal strings and the CSS body (built from sanitize_key'd activity slugs and a hard-coded color palette) is passed through wp_strip_all_tags() as belt-and-suspenders.
  • Security: Wrapped 11 printf( __('...%s...'), ... ); // phpcs:ignore patterns with proper escape functions, eliminating every WordPress.Security.EscapeOutput.OutputNotEscaped ignore 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 use esc_html__(); translations containing inline HTML (e.g. the bookings availability time-zone notice with and tags, the invoice "no-payment-link" notice with edit/settings anchors) use wp_kses() with explicit allowed-tag arrays.
  • Security: Escaped echo $task->id; in clients/view.php (data-attribute context, ×2) with esc_attr().
  • Reliability: Paired the long-lived ob_start() in class-fs-admin.php::handle_early_redirects() with an explicit add_action('shutdown', ...) close. The buffer is intentionally left open across the request lifecycle so controller-level safe_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_VERSION constant to 9.0.9 and updated readme.txt Stable 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 with wp_unslash() and added isset() guards in class-fs-ajax-handler.php (dashboard widget layout, client/invoice/project import lookups, transaction batches, categorization rules). Decoded JSON arrays are also now passed through array_map('sanitize_text_field', ...) before being used in database queries, providing defense in depth even though the values flow through $wpdb->prepare().
  • Security: Sanitized $_GET filter 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 with sanitize_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 with sanitize_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 uses permission_callback => '__return_true' — the endpoint receives push notifications from Google's servers (not authenticated WordPress users) and validates incoming requests via the Google-supplied X-Goog-Channel-ID header against a stored channel ID.
  • Changed: Replaced the inline document.body.classList.add('fs-kanban-page'); block in the kanban tasks view with an admin_body_class filter that adds the class server-side. Removes one of the inline tags 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 Contributors line in readme.txt from jennydougherty to freelancestudioltdco to match the WordPress.org account that hosts the plugin.
Version 9.0.1 1 change
  • Fixed: Removed the Author URI line from the plugin header. The WordPress.org Plugin Directory submission process flagged that Plugin URI and Author URI cannot point to the same address. Since https://freelancestud.io is 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-studio to 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. Internal FS_ constants, class names, database tables, and admin URL slugs are unchanged. The text domain was updated to designosaurus-freelance-studio to match the slug as required by WP.org.
  • Fixed: The @fs_premium_only directive 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 to wp_json_encode() for WordPress-consistent JSON output (40 spots). All $_SERVER reads 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 in sanitize_text_field( wp_unslash( ... ) ) (34 spots). All wp_verify_nonce() calls now sanitize the nonce value with sanitize_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 via wp_enqueue_script(), replacing the previous remote script tag loaded from jsDelivr CDN. The reporting view and client earnings chart now rely on a shared fs-chartjs handle. 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 from code.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 an upload_dir filter to route files into their custom subdirectories (uploads/fs-bug-reports/ and uploads/freelance-studio-receipts/YYYY/MM/) instead of calling move_uploaded_file() directly. Required for WordPress.org Plugin Directory compliance. Multi-file $_FILES arrays are now reshaped into the single-file form wp_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_download feature-gate definition in freelance-studio.php was 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, and active — but only active is a valid project status in this codebase (alongside pending, on_hold, completed, cancelled). Updated to filter by pending and active (the two in-progress states) using the canonical FS_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_wrapper so it cannot affect other admin pages. Includes high-contrast mode overrides.
  • Fixed: Removed a stray closing brace in admin/css/freelance-studio.css that was silently breaking CSS rules below it in the file. The orphan } between #fs-quick-task-form button[type="submit"]:hover and .fs-task-list was 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_only directive so Freemius strips it from the WordPress.org free build entirely. The popup timer was already gated as a Pro feature server-side via fs_studio_is_free_plan() checks, but the view file itself was still shipping in the free ZIP. Hardened the popup handler in FS_Admin::handle_popup_timer() to also check file_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 standalone document and its remaining inline and tags from the WordPress.org free build, addressing the only spot where the plugin loaded WordPress core assets via rather than wp_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_id when created from a project's Documents tab. The proposals table gains a project_id column (migration added for existing installs). Both contract and proposal get_all() methods now support project_id filtering.
  • Fixed: Project dropdown was empty when selecting a client in the recurring invoice form. The get_for_dropdown() method only showed pending and active projects — now also includes on_hold projects.
  • Fixed: Popup timer pause/discard button icons had a white background square behind them. Removed background-color: #fff from .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 to fs-finances with 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's pre_wp_mail filter to route all emails through the configured provider's API. Includes full header parsing (From, Reply-To, CC, Content-Type), automatic fallback to default wp_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\'tdon'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_name instead of deprecated name field), the correct proposal total (total_amount field), 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: addPresetService JS 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_hours and rounded_uninvoiced_hours for 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: matchMedia used 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-only breakpoint 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 to JEEB_FS_ (FS_VERSION → JEEB_FS_VERSION, FS_PLUGIN_DIR → JEEB_FS_PLUGIN_DIR, etc.) to prevent namespace conflicts with Freemius SDK's own FS_ constants.
  • Architecture: Added @fs_premium_only file 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 use file_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(), and fs_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.php to 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-bg CSS 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, and fs_invoice_gradient_direction options 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: 15px to 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-badge override.
  • 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 to FS_Time_Entry model.
Version 6.5.0 3 changes
  • Bug Fix: Fixed WordPress wpdb NULL handling across all models — wpdb->update() and wpdb->insert() convert PHP null to empty strings, which MySQL casts to 0 for bigint columns instead of SQL NULL. 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_Helper utility class with fix_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-primary to 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 .button to .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_status column 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-start to stretch and added overflow-y: hidden on board
  • Bug Fix: Removed max-height from 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_days database 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 no delete case — it fell through to default which just re-rendered the list. Changed to use the same AJAX-based fs-delete-btn pattern that the list view uses, which calls the existing delete_client AJAX 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, and parent_task_id columns 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 requested status 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 (the data: 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, and contractor_signer_title to frontend router's get_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_default property 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_id field 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() and get_internal_tasks() helper methods in Task model
Bug Fixes
  • Fixed SQL ambiguity error in count_by_client() method where status column 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_Project model
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, and retainer_rollover fields 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_periods table 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 use ucfirst() on activity names
  • Added Chart.js integration for reporting page visualizations
  • Added .fs-text-accent CSS 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_init hook to capture PHP 8.1+ deprecation warnings before redirects
  • Fixed: PHP 8.1+ Deprecation Warnings: Added null checks to str_replace() and strpos() 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(), and get_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_source column to invoices table to track creation method
  • Added time_grouping column to invoices table
  • Added show_entry_dates column to invoices table
  • New fs_invoice_items table for detailed line item storage
  • New fs_invoice_projects junction 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_source column to invoices table to track creation method
  • Added time_grouping column to invoices table
  • Added show_entry_dates column to invoices table
  • New fs_invoice_items table for detailed line item storage
  • New fs_invoice_projects junction 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, nofollow meta 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, nofollow meta 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
Freelance Studio
>
Success message!
Warning message!
Error message!