Extending the plugin
The plugin exposes several hooks that allow you to add/modify functionality through WordPress filters. This page lists the available filters and provides example code for some common use cases.
Placeholders
Some hooks contain placeholder {{doctype}}, the value of which is either invoice or estimate, depending on the type of Moneybird document that is being generated. Document type estimate is only available in version 4.0 and newer.
List of contact filter hooks
The following filter hooks can be used to customize contact data and contact reuse logic.
woocommerce_moneybird_contact_detailsFilter array containing the contact details of a given order. These contact details are used to search for a match in the Moneybird contacts, or to create a new Moneybird contact. - Plugin versions: 3.5.0 and newer Filtered object: Array containing the contact details Arguments: (1) WC_Orderwoocommerce_moneybird_contact_queryFilter query string used for looking up existing Moneybird contacts that might be eligible for reuse. Also see woocommerce_moneybird_use_mb_contact. - Plugin versions: 5.27.0 and newer Filtered object: String used as contact lookup query. Arguments: (1) Array: contact details for order at hand (2) WC_Orderwoocommerce_moneybird_contact_updatableFilter a boolean indicating whether a given existing Moneybird contact may be updated with data from the order. - Plugin versions: 3.51.0 and newer Filtered object: Boolean indicating update permission Arguments: (1) Moneybird contact object, (2) Array: contact details extracted from Orderwoocommerce_moneybird_new_contactFilter array containing the fields for a new Moneybird contact. Use this filter to add any additional fields such as `chamber_of_commerce`. - Plugin versions: 2.1.1 and newer Filtered object: Array containing the contact details Arguments: (1) WC_Orderwoocommerce_moneybird_use_mb_contactFilter a boolean indicating whether an existing Moneybird contact may be used for the order at hand. Also refer to woocommerce_moneybird_contact_query for modifying the lookup query for existing Moneybird contacts. - Plugin versions: 5.27.0 and newer Filtered object: Boolean indicating MB contact use Arguments: (1) Moneybird contact object, (2) Array: contact details for order at hand, (3) WC_Order
List of document filter hooks
woocommerce_moneybird_combined_invoice_order_headingFilter the order heading text on combined invoices (i.e. invoices with multiple orders). Default is "*Order {{order_id}}*". The heading is skipped if the filter returns an empty string. - Plugin versions: 5.6.0 and newer Filtered object: String containing the heading text. Arguments: (1) WC_Orderwoocommerce_moneybird_credit_invoiceFilter the credit invoice object before it is pushed to Moneybird. - Plugin versions: 3.0.0 and newer Filtered object: Array containing the complete credit invoice object Arguments: (1) WC_Order: refund object, (2) WC_Order: original orderwoocommerce_moneybird_custom_field_valueFilter the value of a custom field. - Plugin versions: 3.20.0 and newer Filtered object: Value of the custom field for the corresponding WC_Order. Arguments: (1) string: custom field key, (2) int: order idwoocommerce_moneybird_custom_fieldsFilter the array of available custom field keys. - Plugin versions: 3.20.0 and newer Filtered object: Array containing the available custom field keys. Arguments: Nonewoocommerce_moneybird_{{doctype}}Filter the sales invoice or estimate object before it is submitted to Moneybird. - Plugin versions: 2.1.2 and newer Filtered object: Array containing the complete invoice/estimate object Arguments: (1) WC_Order, (2) Array of secondary WC_Orders (in case of combined invoice)woocommerce_moneybird_invoice_couponsFilter invoice lines corresponding to coupon redemptions. - Plugin versions: 3.56 and newer Filtered object: Array of invoice lines (see source for details) Arguments: (1) WC_Orderwoocommerce_moneybird_invoice_itemFilter item details that are put on the Moneybird invoice. Return an empty array to skip the item. - Plugin versions: 2.5 and newer Filtered object: Array of invoice lines (see source for details) Arguments: (1) WC_Order_Item, (2) WC_Orderwoocommerce_moneybird_invoice_shippingFilter invoice lines corresponding to shipping costs. - Plugin versions: 2.5 and newer Filtered object: Array of invoice lines (see source for details) Arguments: (1) WC_Orderwoocommerce_moneybird_invoice_feesFilter invoice lines corresponding to ordering fees. - Plugin versions: 2.5 and newer Filtered object: Array of invoice lines (see source for details) Arguments: (1) WC_Orderwoocommerce_moneybird_invoice_gift_cardsFilter invoice lines corresponding to gift card redemptions. - Plugin versions: 3.49 and newer Filtered object: Array of invoice lines (see source for details) Arguments: (1) WC_Orderwoocommerce_moneybird_invoice_paymentsFilter the array of invoice payments that are submitted to Moneybird for a given WC_Order. - Plugin versions: 5.8.0 and newer Filtered object: Array of payment data arrays. Arguments: (1) WC_Order, (2) Moneybird invoice object.woocommerce_moneybird_{{doctype}}_send_parametersFilter the parameters of the Moneybird API request to send an invoice or estimate. - Plugin versions: 3.48.0 and newer Filtered object: Array containing the API request parameters Arguments: (1) WC_Order, (2) Moneybird invoice/estimate objectwoocommerce_moneybird_{{doctype}}_sequence_idFilter the `{id}` part of the invoice/estimate number, usually in format `{year}-{id}`. The default is empty, causing Moneybird to automatically generate the sequence id upon sending. - Plugin versions: 2.1.1 and newer Filtered object: incremental part of the invoice/estimate id Arguments: (1) WC_Orderwoocommerce_moneybird_is_order_paidFilter the payment status of an order. By default, an order is considered paid if the status is "processing" or "complete", and a payment method has been associated with the order. - Plugin versions: 2.5 and newer Filtered object: Boolean indicating the payment status Arguments: (1) WC_Order, (2) Array of secondary WC_Orders (in case of combined invoice)woocommerce_moneybird_process_orderFilter a boolean indicating whether the specified order should be processed. Returning false allows one to suppress Moneybird contact and invoice generation. - Plugin versions: 3.34.0 and newer Filtered object: Boolean indicating whether order should be processed (default: true). Arguments: (1) WC_Order, (2) string: either 'invoice' or 'estimate'woocommerce_moneybird_referenceFilter the value of the reference field on the invoice. - Plugin versions: 2.1.1 and newer Filtered object: Value of the invoice reference string, for example "order #{{order_id}}" Arguments: (1) WC_Order, (2) Array of secondary WC_Orders (in case of combined invoice)woocommerce_moneybird_register_paymentFilter a boolean indicating whether to register a payment in Moneybird. Use this filter to overwrite the payment registration setting for individual orders. - Plugin versions: 2.1.2 and newer Filtered object: Boolean indicating if the order payment should be registered in Moneybird Arguments: (1) WC_Orderwoocommerce_moneybird_revenue_ledger_accountsFilter the array of available Moneybird revenue ledger accounts. The keys of the associative array start with 's', followed by the id of the ledger account. The values contain the ledger names. - Plugin versions: 3.16.0 and newer Filtered object: Associative array containing the available Moneybird ledger accounts. Arguments: (1) Array: in format s{id} => {ledger_name}.woocommerce_moneybird_payment_amountFilter the payment amount. The default payment amount is equal to the open balance of the invoice (to prevent rounding errors). - Plugin versions: 2.7 and newer Filtered object: Float: payment amount in the store's default currency Arguments: (1) WC_Orderwoocommerce_moneybird_prices_include_taxFilter a boolean indicating whether the prices on the Moneybird document should be specified inclusive of tax. The default is to follow the WooCommerce setting for specifying prices inclusive/exclusive of tax. Deviating from this can lead to rounding errors. - Plugin versions: 3.54.0 and newer Filtered object: Boolean indicating whether prices should be specified inclusive of tax. Arguments: (1) WC_Order, (2) Array of secondary WC_Orders (in case of combined invoice)woocommerce_moneybird_sendmodeFilter the invoice sending mode. - Plugin versions: 3.3.0 and newer Filtered object: String with possible values: 'draft', 'default', 'Manual', 'Email' or 'Simplerinvoicing'. Arguments: (1) WC_Order, (2) Moneybird document (invoice or estimate).
List of action hooks
woocommerce_moneybird_after_{{doctype}}_generateThis action is executed after a Moneybird invoice or estimate has been generated. - Plugin versions: 3.44.0 and newer Arguments: (1) WC_Order instance, (2) Moneybird invoice or estimate object, (3) Array of secondary WC_Orders (in case of combined invoice)woocommerce_moneybird_generate_{{doctype}}_errorThis action is executed if an error occurs during Moneybird document generation. It can be used for example to send a notification to the admin. - Plugin versions: 3.1.3 and newer Arguments: (1) WC_Order instance, (2) string: description of the errorwoocommerce_moneybird_webhookThis action is executed if the webhook is called by Moneybird. A list of all possible events that can trigger a webhook is available here: https://developer.moneybird.com/webhooks/#events - The plugin registers a webhook for the following events: administration_removed, administration_suspended, document_style_destroyed, estimate_mark_accepted, estimate_mark_billed, estimate_mark_rejected, ledger_account_deactivated, ledger_account_destroyed, project_archived, project_destroyed, sales_invoice_destroyed, sales_invoice_merged, sales_invoice_state_changed_to_paid, tax_rate_deactivated, tax_rate_destroyed, workflow_deactivated, workflow_destroyed. - Plugin versions: 5.5.0 and newer Arguments: (1) object: webhook payload, (2) WC_MoneyBird2 instancewoocommerce_moneybird_webhook_{{event}}Same as woocommerce_moneybird_webhook but with the event code included. - Plugin versions: 5.5.0 and newer Arguments: (1) object: webhook payload, (2) WC_MoneyBird2 instance
Access invoice from front-end
If you want to provide customers with a link to their invoice(s) you can use the following code to access the invoice linked to a WooCommerce order:
$moneybird = WCMB(); // This loads the registered WC_MoneyBird2 instance
$invoice = $moneybird->get_invoice_from_order_id($order_id);
if ($invoice) {
var_dump($invoice); // Replace this with code to output info about the invoice
}
Add VAT/CoC number to contacts
Support for the EU VAT numbers plugin is built-in since v2.5.9. The plugin checks the following order meta fields for a VAT number: vat_number, VAT Number, billing_eu_vat_number, billing_vat_number (with or without underscore prepended). If one of these fields contains a VAT number, it is automatically passed to Moneybird. Almost all EU VAT plugins store the VAT number in one of the mentioned fields, so it should work out-of-the-box.
However, some custom code might be required to pass VAT numbers to Moneybird if you use another plugin to collect the VAT number.
You can add a piece of code to functions.php such that the VAT numbers of customers get passed on to Moneybird. Modify the code below to read the VAT number from the correct location (depends on the plugin used for collecting the VAT number). It is also possible the pass the Chamber of Commerce registration number (“KvK nummer” in Dutch) to Moneybird (see the commented line in the example code).
function filter_woocommerce_moneybird_new_contact($contact, $order) {
// Add VAT number from "EU VAT Number" plugin to Moneybird contact
$order_id = is_callable(array($order, 'get_id')) ? $order->get_id() : $order->id;
$vat_number = get_post_meta($order_id, '_vat_number', true); // Modify to read the correct field
if ($vat_number) {
$contact['tax_number'] = $vat_number;
}
// $contact['chamber_of_commerce'] = 'FILL THIS FIELD IF NEEDED';
return $contact;
}
add_filter('woocommerce_moneybird_contact_details', 'filter_woocommerce_moneybird_new_contact', 10, 2);
Example: order-dependent invoice workflow
Edit and paste the following code snippet in functions.php to make the workflow of the invoice dependent on the properties of the WooCommerce order. For example, we can use a different workflow for orders in the German language:
// The following filter modifies the invoice workflow based on the WooCommerce order.
// $order contains the WC_Order instance corresponding to the order for which the invoice is being generated.
function filter_woocommerce_moneybird_modify_workflow($invoice, $order) {
// Use the $order object here to look up the required information
$order_id = is_callable(array($order, 'get_id')) ? $order->get_id() : $order->id;
$language = get_post_meta($order_id, 'wpml_language', true);
if ($language == 'de') {
// Note: the workflow id can be extracted from the url when editing it in Moneybird.
$invoice['workflow_id'] = '136261670020318887';
}
return $invoice;
}
add_filter('woocommerce_moneybird_invoice', 'filter_woocommerce_moneybird_modify_workflow', 10, 2);
Example: ignore non-virtual products when generating invoices
The code snippet below provides an example of how to filter order items when generating an invoice.
function mb_invoice_item_filter($item, $wc_order_item, $wc_order) {
// Ignore non-virtual products when generating invoices
$product = apply_filters('woocommerce_order_item_product', $wc_order->get_product_from_item($wc_order_item), $wc_order_item);
if (!$product->is_virtual()) {
$item = array();
}
return $item;
}
add_filter('woocommerce_moneybird_invoice_item', 'mb_invoice_item_filter', 10, 3);
Example: add Subscription properties as custom fields
If you use WooCommerce Subscriptions, you might want to make certain properties of subscriptions available as custom fields, so they can be mapped to custom invoice/contact fields (“Extra Velden”) in Moneybird. The following example code illustrates how this can be achieved.
function insert_subscription_custom_fields($custom_fields) {
// Add user-defined custom field keys to the list of available custom fields.
$custom_fields[] = 'subscription_start_date';
return $custom_fields;
}
add_filter('woocommerce_moneybird_custom_fields', 'insert_subscription_custom_fields', 10, 1);
function resolve_subscription_custom_field_values($val, $key, $order_id) {
// Resolve the value of all user-defined custom fields (as specified in `insert_subscription_custom_fields`).
if (!in_array($key, array('subscription_start_date'))) {
// We don't have to resolve this custom field
return $val;
}
// Get subscriptions associated with the order
$subscriptions = wcs_get_subscriptions_for_order($order_id);
if (!$subscriptions) {
$subscriptions = wcs_get_subscriptions_for_renewal_order($order_id);
}
if ($subscriptions) {
if ($key == 'subscription_start_date') {
foreach ($subscriptions as $subscription) {
$start_date = $subscription->get_time('date_created');
if ($start_date) {
$val = date('d-m-Y', $start_date);
break;
}
}
}
}
return $val;
}
add_filter('woocommerce_moneybird_custom_field_value', 'resolve_subscription_custom_field_values', 10, 3);
Example: change ledger account based on country
Use the following example code to change the Moneybird revenue ledger account (omzetcategorie) for all invoice lines if the country of the buyer is not NL.
function filter_woocommerce_moneybird_modify_ledger_account($invoice, $order) {
// Use the $order object here to look up the required information
if (strtolower($order->get_billing_country()) != 'nl') {
// Note: the ledger account id can be extracted from the url when editing it in Moneybird.
for ($i=0; $i<count($invoice['details_attributes']); $i++) {
$invoice['details_attributes'][$i]['ledger_account_id'] = '123456789'; # TODO: use correct id here
}
}
return $invoice;
}
add_filter('woocommerce_moneybird_invoice', 'filter_woocommerce_moneybird_modify_ledger_account', 10, 2);
Example: modify contact details
The following example code replaces the default values of contact fields with order meta field values.
Additionally, you can fill contact fields that are not filled by default. In the example, the “T.a.v. facturen” field is filled, corresponding to the send_invoices_to_attention field in the Moneybird API. Refer to the Moneybird Contacts API documentation for a full overview of the available fields.
function wc_mb_modify_contact_details($contact_details, $order) {
// Replace values in $contact_details array with values from custom meta fields
// This overwrites the default field values. To clear a value, use:
// $contact_details['firstname'] = ''; // Empty value
$order_id = $order->get_id();
$contact_details['company_name'] = get_post_meta($order_id, '_custom_field_name', true);
$contact_details['firstname'] = get_post_meta($order_id, '_custom_field_name', true);
$contact_details['lastname'] = get_post_meta($order_id, '_custom_field_name', true);
$contact_details['address1'] = get_post_meta($order_id, '_custom_field_name', true);
$contact_details['address2'] = get_post_meta($order_id, '_custom_field_name', true);
$contact_details['zipcode'] = get_post_meta($order_id, '_custom_field_name', true);
$contact_details['city'] = get_post_meta($order_id, '_custom_field_name', true);
$contact_details['country'] = get_post_meta($order_id, '_custom_field_name', true);
$contact_details['email'] = get_post_meta($order_id, '_custom_field_name', true);
$contact_details['phone'] = get_post_meta($order_id, '_custom_field_name', true);
// Fill the "T.a.v. facturen" field of Moneybird contact
$contact_details['send_invoices_to_attention'] = get_post_meta($order_id, '_custom_field_name', true);
return $contact_details;
}
add_filter('woocommerce_moneybird_contact_details', 'wc_mb_modify_contact_details', 10, 2);
Example: reuse contact based on Chamber of Commerce number
The following example forces the plugin to use an existing Moneybird contact if and only if the Chamber of Commerce (“KvK”) number matches. To facilitate this, both the contact lookup query and the contact reuse condition logic are customized.
add_filter('woocommerce_moneybird_contact_query', function($query, $contact_details, $wc_order) {
// Lookup existing Moneybird contacts based on chamber of commerce number.
if (!empty($contact_details['chamber_of_commerce'])) {
$query = $contact_details['chamber_of_commerce'];
}
return $query;
}, 10, 3);
add_filter('woocommerce_moneybird_use_mb_contact', function($use_mb_contact, $mb_contact, $contact_details, $wc_order) {
// Use existing Moneybird contact if and only if chamber of commerce number matches.
if (!empty($contact_details['chamber_of_commerce'])) {
if (trim($contact_details['chamber_of_commerce']) == trim($mb_contact->chamber_of_commerce)) {
return true;
}
}
return false;
}, 10, 3);
Example: force prices on invoice to be inclusive/exclusive of tax
The plugin follows the WooCommerce setting for prices being inclusive of exclusive of tax. If product prices are inclusive of tax, the invoice will also have invoice lines inclusive of tax and vice versa.
Code to force the invoice prices to be exclusive of tax:
// The following filter forces the invoice to have prices EXCLUSIVE of tax.
function force_moneybird_prices_exclude_tax($include_tax, $order) {
return false;
}
add_filter('woocommerce_moneybird_prices_include_tax', 'force_moneybird_prices_exclude_tax', 10, 2);
Code to force the invoice prices to be inclusive of tax:
// The following filter forces the invoice to have prices INCLUSIVE of tax.
function force_moneybird_prices_include_tax($include_tax, $order) {
return true;
}
add_filter('woocommerce_moneybird_prices_include_tax', 'force_moneybird_prices_include_tax', 10, 2);
Example: include product properties on invoice line
A WooCommerce product can have custom properties, for example “Height” or “Course date”. Such product properties are not saved in the Order, and will not be included on invoices by default. You can use the following code to add all textual product properties that are visible on the product page to the corresponding invoice line.
function wcmb_insert_product_properties($invoice_item, $item, $order) {
$product = apply_filters('woocommerce_order_item_product', $order->get_product_from_item($item), $item);
if (!$product) {
// Corresponding product is not available
return $invoice_item;
}
foreach ($product->get_attributes() as $attr_code => $attr) {
// Only include text properties that are marked as "visible on product page"
if ($attr->get_visible() && !($attr->is_taxonomy())) {
$values = array();
foreach ($attr->get_options() as $val) {
if (is_string($val) && !empty($val)) {
$values[] = $val;
}
}
if ($values) {
// Add the following to the invoice item description: white line, property name in bold, property value on separate line(s)
$invoice_item['description'] .= "\n\n*" . $attr->get_name() . "*:\n" . strip_tags(implode("\n", $values));
}
}
}
return $invoice_item;
}
add_filter('woocommerce_moneybird_invoice_item', 'wcmb_insert_product_properties', 10, 3);