skip to Main Content

I am using WooCommerce Subscriptions to manage recurring payments on my WordPress site, which sells baby diapers.

I want to add additional detail to my subscriptions, so that my customers can differentiate between their subscriptions in other ways than by subscription id.

I capture leads about the customers baby, including their name, in a form at the beginning of the customers journey.

To add my extra detail field to the subscriptions data, I modified the wcs_create_subscription function located here:

wp-content/plugins/woocommerce-subscriptions/vendor/woocommerce/subscriptions-core/wcs-functions.php

by first adding a ‘baby_name’ argument to the $default_args array, that I have set to store the current users id with get_current_user_id(), just to test the functionality:

$default_args = array(
    'status'             => '',
    'baby_name'          => get_current_user_id(),
    'order_id'           => 0,
    'customer_note'      => null,
    'customer_id'        => ( ! empty( $order ) ) ? $order->get_user_id() : null,
    'start_date'         => $default_start_date,
    'date_created'       => $now,
    'created_via'        => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'created_via' ) : '',
    'order_version'      => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'version' ) : WC_VERSION,
    'currency'           => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'currency' ) : get_woocommerce_currency(),
    'prices_include_tax' => ( ! empty( $order ) ) ? ( ( wcs_get_objects_property( $order, 'prices_include_tax' ) ) ? 'yes' : 'no' ) : get_option( 'woocommerce_prices_include_tax' ), // we don't use wc_prices_include_tax() here because WC doesn't use it in wc_create_order(), not 100% sure why it doesn't also check the taxes are enabled, but there could forseeably be a reason
);

Then I run a update_post_meta() function to save my argument in the subscriptions database:

update_post_meta( $subscription_id, '_baby_name', $args['baby_name'] );

Here is my full wcs_create_subscription function:

/**
 * Create a new subscription
 *
 * Returns a new WC_Subscription object on success which can then be used to add additional data.
 *
 * @return WC_Subscription | WP_Error A WC_Subscription on success or WP_Error object on failure
 * @since  2.0
 */
function wcs_create_subscription( $args = array() ) {

    $now   = gmdate( 'Y-m-d H:i:s' );
    $order = ( isset( $args['order_id'] ) ) ? wc_get_order( $args['order_id'] ) : null;

    if ( ! empty( $order ) ) {
        $default_start_date = wcs_get_datetime_utc_string( wcs_get_objects_property( $order, 'date_created' ) );
    } else {
        $default_start_date = ( isset( $args['date_created'] ) ) ? $args['date_created'] : $now;
    }

    $default_args = array(
        'status'             => '',
        'baby_name'          => get_current_user_id(),
        'order_id'           => 0,
        'customer_note'      => null,
        'customer_id'        => ( ! empty( $order ) ) ? $order->get_user_id() : null,
        'start_date'         => $default_start_date,
        'date_created'       => $now,
        'created_via'        => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'created_via' ) : '',
        'order_version'      => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'version' ) : WC_VERSION,
        'currency'           => ( ! empty( $order ) ) ? wcs_get_objects_property( $order, 'currency' ) : get_woocommerce_currency(),
        'prices_include_tax' => ( ! empty( $order ) ) ? ( ( wcs_get_objects_property( $order, 'prices_include_tax' ) ) ? 'yes' : 'no' ) : get_option( 'woocommerce_prices_include_tax' ), // we don't use wc_prices_include_tax() here because WC doesn't use it in wc_create_order(), not 100% sure why it doesn't also check the taxes are enabled, but there could forseeably be a reason
    );

    $args              = wp_parse_args( $args, $default_args );
    $subscription_data = array();

    // Validate the date_created arg.
    if ( ! is_string( $args['date_created'] ) || false === wcs_is_datetime_mysql_format( $args['date_created'] ) ) {
        return new WP_Error( 'woocommerce_subscription_invalid_date_created_format', _x( 'Invalid created date. The date must be a string and of the format: "Y-m-d H:i:s".', 'Error message while creating a subscription', 'woocommerce-subscriptions' ) );
    } elseif ( wcs_date_to_time( $args['date_created'] ) > current_time( 'timestamp', true ) ) {
        return new WP_Error( 'woocommerce_subscription_invalid_date_created', _x( 'Subscription created date must be before current day.', 'Error message while creating a subscription', 'woocommerce-subscriptions' ) );
    }

    // Validate the start_date arg.
    if ( ! is_string( $args['start_date'] ) || false === wcs_is_datetime_mysql_format( $args['start_date'] ) ) {
        return new WP_Error( 'woocommerce_subscription_invalid_start_date_format', _x( 'Invalid date. The date must be a string and of the format: "Y-m-d H:i:s".', 'Error message while creating a subscription', 'woocommerce-subscriptions' ) );
    }

    // check customer id is set
    if ( empty( $args['customer_id'] ) || ! is_numeric( $args['customer_id'] ) || $args['customer_id'] <= 0 ) {
        return new WP_Error( 'woocommerce_subscription_invalid_customer_id', _x( 'Invalid subscription customer_id.', 'Error message while creating a subscription', 'woocommerce-subscriptions' ) );
    }

    // check the billing period
    if ( empty( $args['billing_period'] ) || ! in_array( strtolower( $args['billing_period'] ), array_keys( wcs_get_subscription_period_strings() ) ) ) {
        return new WP_Error( 'woocommerce_subscription_invalid_billing_period', __( 'Invalid subscription billing period given.', 'woocommerce-subscriptions' ) );
    }

    // check the billing interval
    if ( empty( $args['billing_interval'] ) || ! is_numeric( $args['billing_interval'] ) || absint( $args['billing_interval'] ) <= 0 ) {
        return new WP_Error( 'woocommerce_subscription_invalid_billing_interval', __( 'Invalid subscription billing interval given. Must be an integer greater than 0.', 'woocommerce-subscriptions' ) );
    }

    $subscription_data['post_type']     = 'shop_subscription';
    $subscription_data['post_status']   = 'wc-' . apply_filters( 'woocommerce_default_subscription_status', 'pending' );
    $subscription_data['ping_status']   = 'closed';
    $subscription_data['post_author']   = 1;
    $subscription_data['post_password'] = uniqid( 'order_' );
    // translators: Order date parsed by strftime
    $post_title_date = strftime( _x( '%b %d, %Y @ %I:%M %p', 'Used in subscription post title. "Subscription renewal order - <this>"', 'woocommerce-subscriptions' ) ); // phpcs:ignore WordPress.WP.I18n.UnorderedPlaceholdersText
    // translators: placeholder is order date parsed by strftime
    $subscription_data['post_title']    = sprintf( _x( 'Subscription &ndash; %s', 'The post title for the new subscription', 'woocommerce-subscriptions' ), $post_title_date );
    $subscription_data['post_date_gmt'] = $args['date_created'];
    $subscription_data['post_date']     = get_date_from_gmt( $args['date_created'] );

    if ( $args['order_id'] > 0 ) {
        $subscription_data['post_parent'] = absint( $args['order_id'] );
    }

    if ( ! is_null( $args['customer_note'] ) && ! empty( $args['customer_note'] ) ) {
        $subscription_data['post_excerpt'] = $args['customer_note'];
    }

    // Only set the status if creating a new subscription, use wcs_update_subscription to update the status
    if ( $args['status'] ) {
        if ( ! in_array( 'wc-' . $args['status'], array_keys( wcs_get_subscription_statuses() ) ) ) {
            return new WP_Error( 'woocommerce_invalid_subscription_status', __( 'Invalid subscription status given.', 'woocommerce-subscriptions' ) );
        }
        $subscription_data['post_status']  = 'wc-' . $args['status'];
    }

    $subscription_id = wp_insert_post( apply_filters( 'woocommerce_new_subscription_data', $subscription_data, $args ), true );

    if ( is_wp_error( $subscription_id ) ) {
        return $subscription_id;
    }

    // Default order meta data.
    update_post_meta( $subscription_id, '_order_key', wcs_generate_order_key() );
    update_post_meta( $subscription_id, '_order_currency', $args['currency'] );
    update_post_meta( $subscription_id, '_prices_include_tax', $args['prices_include_tax'] );
    update_post_meta( $subscription_id, '_created_via', sanitize_text_field( $args['created_via'] ) );

    // add/update the billing
    update_post_meta( $subscription_id, '_billing_period', $args['billing_period'] );
    update_post_meta( $subscription_id, '_billing_interval', absint( $args['billing_interval'] ) );

    update_post_meta( $subscription_id, '_customer_user', $args['customer_id'] );
    update_post_meta( $subscription_id, '_order_version', $args['order_version'] );

    update_post_meta( $subscription_id, '_schedule_start', $args['start_date'] );
    update_post_meta( $subscription_id, '_baby_name', $args['baby_name'] );

    /**
     * Filter the newly created subscription object.
     *
     * @since 2.2.22
     * @param WC_Subscription $subscription
     */
    $subscription = apply_filters( 'wcs_created_subscription', wcs_get_subscription( $subscription_id ) );

    /**
     * Triggered after a new subscription is created.
     *
     * @since 2.2.22
     * @param WC_Subscription $subscription
     */
    do_action( 'wcs_create_subscription', $subscription );

    return $subscription;
}

I can confirm that this works, as I can see a row with _baby_name in the meta_key field and my user id in the meta_value field for a subscription with id 2898 that I placed recently in my sites _postmeta database table:

PHP My Admin showing sites _postmeta database table

As I know that I should never modify the core plugin files, I am looking to make my modifications in a snippet or similar that I can place in my child themes function.php file. Any advice?

2

Answers


  1. From the code you have posted it can be deduced that use can be made of the wcs_create_subscription action hook:

    /**
     * Triggered after a new subscription is created.
     *
     * @since 2.2.22
     * @param WC_Subscription $subscription
     */
    function action_wcs_create_subscription( $subscription ) {
        // Get ID
        $subscription_id = $subscription->get_id();
    
        update_post_meta( $subscription_id, '_baby_name', 'my_value' );
    }
    add_action( 'wcs_create_subscription', 'action_wcs_create_subscription', 10, 1 );
    

    There is no need to add this as an argument first. Via $subscription you can obtain multiple data, if desired

    Login or Signup to reply.
  2. With the new HPOS functionality that comes with WooCommerce 7.3, no longer is recommended to use post meta. You should use:

    $subscription->update_meta_data( '_baby_name', 'my_value' );
    $subscription->save();
    

    Where the $subscription is the object from subscription. If you haven’t loaded, you can use the function:

    $subscription = wcs_get_subscription( $sub_id );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search