data = $id_or_data; $this->id = isset($id_or_data['id']) ? (int) $id_or_data['id'] : 0; } else { $this->id = (int) $id_or_data; // Load data from user meta if we have a valid ID if ($this->id > 0) { $this->loadFromUserMeta(); } } } /** * Magic method to get dynamic properties * * @since 1.0.0 * @param string $name Property name * @return mixed Property value */ public function __get($name) { // Handle special properties if ($name === 'id') { return $this->id; } // Return from dynamic data array return $this->data[$name] ?? null; } /** * Magic method to set dynamic properties * * @since 1.0.0 * @param string $name Property name * @param mixed $value Property value */ public function __set($name, $value) { // Handle special properties if ($name === 'id') { $this->id = $value; return; } // Store in dynamic data array $this->data[$name] = $value; $this->is_dirty = true; } /** * Magic method to check if property exists * * @since 1.0.0 * @param string $name Property name * @return bool */ public function __isset($name) { if ($name === 'id') { return isset($this->id); } return isset($this->data[$name]); } /** * Dynamic getter method * * @since 1.0.0 * @param string $name Method name * @param array $arguments Method arguments * @return mixed */ public function __call($name, $arguments) { // Handle getter methods (getFieldName) if (strpos($name, 'get') === 0) { $field_name = $this->camelCaseToSnakeCase(substr($name, 3)); // Remove 'get' prefix return $this->__get($field_name); } // Handle setter methods (setFieldName) if (strpos($name, 'set') === 0) { $field_name = $this->camelCaseToSnakeCase(substr($name, 3)); // Remove 'set' prefix $value = $arguments[0] ?? null; $this->__set($field_name, $value); return null; } // Handle isset methods (isFieldName) if (strpos($name, 'is') === 0) { $field_name = $this->camelCaseToSnakeCase(substr($name, 2)); // Remove 'is' prefix return (bool) $this->__get($field_name); } // Handle has methods (hasFieldName) if (strpos($name, 'has') === 0) { $field_name = $this->camelCaseToSnakeCase(substr($name, 3)); // Remove 'has' prefix return !empty($this->__get($field_name)); } throw new \BadMethodCallException(esc_html("Method $name does not exist")); } /** * Convert camelCase to snake_case * * @since 1.0.0 * @param string $camelCase * @return string */ private function camelCaseToSnakeCase($camelCase) { return strtolower(preg_replace('/(?id <= 0) { return; } // Easy-Invoice-owned meta (what the user explicitly set through this plugin). $this->data['business_client_name'] = get_user_meta($this->id, ClientFields::BUSINESS_CLIENT_NAME, true); $this->data['email'] = get_user_meta($this->id, ClientFields::EMAIL, true); $this->data['username'] = get_user_meta($this->id, ClientFields::USERNAME, true); $this->data['address'] = get_user_meta($this->id, ClientFields::ADDRESS, true); $this->data['extra_info'] = get_user_meta($this->id, ClientFields::EXTRA_INFO, true); $this->data['first_name'] = get_user_meta($this->id, ClientFields::FIRST_NAME, true); $this->data['last_name'] = get_user_meta($this->id, ClientFields::LAST_NAME, true); $this->data['website'] = get_user_meta($this->id, ClientFields::WEBSITE, true); $this->data['phone'] = get_user_meta($this->id, ClientFields::PHONE, true); // Fallback chain for clients NOT created through Easy Invoice // (typically WooCommerce customers imported via order placement, // or plain WP users with profile fields filled in): // // 1. EI meta (above) — explicit entry in Easy Invoice // 2. WP standard meta — user profile / WC sync // 3. WC billing_* meta — set the first time a customer checks out // // Without this fallback, WooCommerce customers render as their bare // user_login (e.g. "callum_smith42") everywhere — Clients listing, // invoice builder client-search dropdown, and invoice header — even // though their real name sits in billing_first_name / billing_last_name. $user = get_user_by('id', $this->id); if (empty($this->data['email'])) { $this->data['email'] = $user ? (string) $user->user_email : ''; if (empty($this->data['email'])) { $this->data['email'] = (string) get_user_meta($this->id, 'billing_email', true); } } if (empty($this->data['username'])) { $this->data['username'] = $user ? (string) $user->user_login : ''; } if (empty($this->data['first_name'])) { $this->data['first_name'] = $user ? (string) $user->first_name : ''; if (empty($this->data['first_name'])) { $this->data['first_name'] = (string) get_user_meta($this->id, 'billing_first_name', true); } } if (empty($this->data['last_name'])) { $this->data['last_name'] = $user ? (string) $user->last_name : ''; if (empty($this->data['last_name'])) { $this->data['last_name'] = (string) get_user_meta($this->id, 'billing_last_name', true); } } if (empty($this->data['business_client_name'])) { $this->data['business_client_name'] = (string) get_user_meta($this->id, 'billing_company', true); } if (empty($this->data['phone'])) { $this->data['phone'] = (string) get_user_meta($this->id, 'billing_phone', true); } } // Essential methods only public function getId(): int { return $this->id; } public function setId(int $id): void { $this->id = $id; } public function isDirty(): bool { return $this->is_dirty; } public function resetDirty() { $this->is_dirty = false; return $this; } public function toArray(): array { return array_merge(['id' => $this->id], $this->data); } }