Skip to content

API create_customer drops date custom fields (double date parse) #21

Description

@alllexandrz

Impacted plugin

Jetpack

Quick summary

Contact date custom fields are not saved when creating/updating a contact via the CRM REST/API create_customer endpoint, even when a valid Y-m-d value is sent and the API response looks successful.

Root cause: the date is converted to a Unix timestamp once in api/create_customer.php, then converted again inside zeroBS_addUpdateCustomer() → zeroBS_buildContactMeta(). The second pass expects Y-m-d, receives a timestamp string, fails parsing (false), and removeEmpties=true strips the field before save.

Steps to reproduce

In Jetpack CRM → Settings → Custom Fields, create a Contact custom field of type Date (example label: Contract Date, slug e.g. contract-date).

Enable the CRM API and note the API key/secret.

POST to the create/update customer API endpoint with JSON similar to:

{
"email": "apitest-date-cf@example.com",
"fname": "API",
"lname": "DateTest",
"status": "Customer",
"contract-date": "2026-07-23"
}

Confirm the API response returns success / echoes the payload (including the date).

Open the contact in CRM admin, or fetch via the customers API (withCustomFields is enabled there), or query wp_zbs_customfields for the contact.

Expected

contract-date is stored as a Unix timestamp (UTS) and shown as 2026-07-23 in the contact UI / API read responses.

Actual

The contact is created/updated, but the date custom field is missing/empty. The create endpoint response is misleading because it returns the request payload, not the persisted custom-field state.

Technical root cause

Pass 1 — api/create_customer.php

$customer_array = zeroBS_buildContactMeta( $new_customer, array(), '', 'zbsc_', $remove_empties, $autogen_autonumbers );

Input key: contract-date = "2026-07-23"

Date branch in zeroBS_buildObjArr():

case 'date':
$retArray[ $outputPrefix . $fK ] = jpcrm_date_str_to_uts( $safe_text, '!Y-m-d', true );

Result: zbsc_contract-date = e.g. 1784764800 (int UTS)

Pass 2 — zeroBS_addUpdateCustomer() in includes/ZeroBSCRM.DAL3.Helpers.php

$zbsCustomerMeta = zeroBS_buildContactMeta( $cFields, $existingMeta, $metaBuilderPrefix, '', true );

Re-reads zbsc_contract-date (already UTS)

Date branch again runs jpcrm_date_str_to_uts( '1784764800', '!Y-m-d', true )

DateTime::createFromFormat( '!Y-m-d', '1784764800' ) fails → false

With $removeEmpties = true, empty(false) removes the key

addUpdateContact() never receives the custom field value

Same pattern exists for companies (api/create_company.php + zeroBS_addUpdateCompany / shared zeroBS_buildObjArr date handling).

Site owner impact

More than 60% of the total website/platform users

Severity

Critical

What other impact(s) does this issue have?

Platform revenue

If a workaround is available, please outline it here.

Suggested fix

One of:

Skip re-normalization for already-parsed UTS in the date case of zeroBS_buildObjArr():

case 'date':
$raw = $arraySource[ $fieldPrefix . $fK ];
if ( is_numeric( $raw ) ) {
$retArray[ $outputPrefix . $fK ] = (int) $raw;
break;
}
$safe_text = sanitize_text_field( $raw );
$retArray[ $outputPrefix . $fK ] = jpcrm_date_str_to_uts( $safe_text, '!Y-m-d', true );
break;

Or stop calling zeroBS_buildContactMeta twice in the API → zeroBS_addUpdateCustomer path (pass already-built meta through, or only sanitize once).

Add a regression test: API create contact with a date custom field, assert custom field row exists with expected UTS.

Platform (Simple and/or Atomic)

Self-hosted

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingready-for-agentFully specified, ready for an AFK agent

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions