skip to Main Content

I have existing code that has been working fine with the former WooCommerce PayPal Payment Gateway, but now that this has been abandoned in favour of a new version, WooCommerce PayPal Payments I am getting a conflict with some custom code I am using to edit the headings of some custom fields I am using on the checkout page.

I used the solution provided here; ie:

// -- add heading type
add_filter( 'woocommerce_form_field_heading','wpwp_checkout_fields_heading', 99, 4 );

function wpwp_checkout_fields_heading($field, $key, $args, $value) {
    $output = '<h3 class="form-row form-row-wide">'.__( $args['label'], 'woocommerce' ).'</h3>';
    echo $output;
}

// -- modify checkout fields
add_action( 'woocommerce_checkout_fields', 'wpwp_checkout_fields', 10, 1 );

function wpwp_checkout_fields($fields) {
    // add custom heading
    $fields['billing']['billing_email_heading'] = array(
        'type'      => 'heading',
        'label'     => 'Contact Information'
    );

    $fields['billing']['billing_email_subscribe'] = array(
        'type'      => 'checkbox',
        'label'     => 'Keep me up to date on news and exclusive offers.',
        'required'     => false
    );

    $fields['billing']['billing_address_heading'] = array(
        'type'      => 'heading',
        'label'     => 'Billing address'
    );

    // rename billing fields
    $fields['billing']['billing_address_1']['label'] = 'Address';
    $fields['billing']['billing_city']['label'] = 'City';

    // re-order billing fields
    $fields['billing']['billing_email_heading']['priority'] = 10;
    $fields['billing']['billing_email']['priority'] = 20;
    $fields['billing']['billing_email_subscribe']['priority'] = 25;

    $fields['billing']['billing_address_heading']['priority'] = 29;
    $fields['billing']['billing_first_name']['priority'] = 30;
    $fields['billing']['billing_last_name']['priority'] = 40;

    $fields['billing']['billing_company']['priority'] = 45;

    $fields['billing']['billing_address_1']['priority'] = 50;
    $fields['billing']['billing_address_2']['priority'] = 60;
    $fields['billing']['billing_city']['priority'] = 70;

    $fields['billing']['billing_country']['priority'] = 80;
    $fields['billing']['billing_state']['priority'] = 90;
    $fields['billing']['billing_postcode']['priority'] = 100;
    $fields['billing']['billing_phone']['priority'] = 110;

    // Change certain fields to optional
    $fields['billing']['billing_phone']['required'] = false;

    // rename shipping fields
    $fields['shipping']['shipping_address_1']['label'] = 'Address';
    $fields['shipping']['shipping_city']['label'] = 'City';

    // re-order shipping fields
    $fields['shipping']['shipping_first_name']['priority'] = 20;
    $fields['shipping']['shipping_last_name']['priority'] = 30;

    $fields['shipping']['shipping_company']['priority'] = 35;

    $fields['shipping']['shipping_address_1']['priority'] = 40;
    $fields['shipping']['shipping_address_2']['priority'] = 50;
    $fields['shipping']['shipping_city']['priority'] = 60;

    $fields['shipping']['shipping_country']['priority'] = 70;
    $fields['shipping']['shipping_state']['priority'] = 80;
    $fields['shipping']['shipping_postcode']['priority'] = 90;

    // add heading to order notes
    $fields['order']['order_comments_heading'] = array(
        'type'      => 'heading',
        'label'     => 'Additional information'
    );

    // re-order order fields
    $fields['order']['order_comments_heading']['priority'] = 10;
    $fields['order']['order_comments']['priority'] = 20;

    return $fields;
}

But when I go to the checkout page I get this error:

Fatal error: Uncaught TypeError: Return value of WooCommercePayPalCommerceWcGatewaySettingsSettingsRenderer::render_multiselect() must be of the type string, null returned in **************/wp-content/plugins/woocommerce-paypal-payments/modules/ppcp-wc-gateway/src/Settings/SettingsRenderer.php:198

The code for this section is:

/**
 * Renders the multiselect field.
 *
 * @param string $field The current field HTML.
 * @param string $key   The current key.
 * @param array  $config The configuration array.
 * @param string $value The current value.
 *
 * @return string
 */
public function render_multiselect( $field, $key, $config, $value ): string {

    if ( 'ppcp-multiselect' !== $config['type'] ) {
        return $field; // This is line 198
    }

    $options = array();
    foreach ( $config['options'] as $option_key => $option_value ) {
        $selected = ( in_array( $option_key, $value, true ) ) ? 'selected="selected"' : '';

        $options[] = '<option value="' . esc_attr( $option_key ) . '" ' . $selected . '>' .
        esc_html( $option_value ) .
        '</option>';
    }

    $html = sprintf(
        '<select
                    multiple
                     class="%s"
                     name="%s"
                 >%s</select>',
        esc_attr( implode( ' ', isset( $config['input_class'] ) ? $config['input_class'] : array() ) ),
        esc_attr( $key ) . '[]',
        implode( '', $options )
    );

    return $html;
}

Line 198 is near the top of that code and I have inserted a comment denoting it.

In the below file from the new payment gateway plugin, which is located at wp-contentpluginswoocommerce-paypal-paymentsmodulesppcp-wc-gatewaysrcWCGatewayModule.php I have found the below, which may be relevant:

add_filter(
    'woocommerce_form_field',
    static function ( $field, $key, $args, $value ) use ( $container ) {
        $renderer = $container->get( 'wcgateway.settings.render' );
        /**
         * The Settings Renderer object.
         *
         * @var SettingsRenderer $renderer
         */
        $field = $renderer->render_multiselect( $field, $key, $args, $value );
        $field = $renderer->render_password( $field, $key, $args, $value );
        $field = $renderer->render_text_input( $field, $key, $args, $value );
        $field = $renderer->render_heading( $field, $key, $args, $value );
        $field = $renderer->render_table( $field, $key, $args, $value );
        return $field;
    },
    10,
    4
);

Is there any problems in my code that I can do to fix this issue?

2

Answers


  1. Chosen as BEST ANSWER

    It appears the solution is that you have to return the output from the function that is called from the call to the woocommerce_form_field_heading filter, instead of echoing it.

    add_filter( 'woocommerce_form_field_heading','wpwp_checkout_fields_heading', 99, 4 );
    function wpwp_checkout_fields_heading($field, $key, $args, $value) {
        $output = '<h3 class="form-row form-row-wide">'.__( $args['label'], 'woocommerce' ).'</h3>';
        return $output;
    }
    

    It seems my call to the woocommerce_form_field_heading filter conflicted with the render_multiselect function call, which was called within the anonymous function listed above, in the call to the woocommerce_form_field filter:

    add_filter(
        'woocommerce_form_field',
        static function ( $field, $key, $args, $value ) use ( $container ) {
            $renderer = $container->get( 'wcgateway.settings.render' );
            /**
             * The Settings Renderer object.
             *
             * @var SettingsRenderer $renderer
             */
            $field = $renderer->render_multiselect( $field, $key, $args, $value );
            $field = $renderer->render_password( $field, $key, $args, $value );
            $field = $renderer->render_text_input( $field, $key, $args, $value );
            $field = $renderer->render_heading( $field, $key, $args, $value );
            $field = $renderer->render_table( $field, $key, $args, $value );
            return $field;
        },
        10,
        4
    );
    

    I'm not entirely sure how they interact, but I'm assuming that woocommerce_form_field_heading gets called during calls to woocommerce_form_field and thus my echo statement interrupted the flow, and thus me echo'ing the data, instead of returning it, ended up with null being returned, and not a string, of which produced the error.


  2.     /**
         * Renders the multiselect field.
         *
         * @param string $field The current field HTML.
         * @param string $key   The current key.
         * @param array  $config The configuration array.
         * @param string $value The current value.
         *
         * @return string
         */
        public function render_multiselect( $field, $key, $config, $value ): ?string
     {
        
            if ( 'ppcp-multiselect' !== $config['type'] ) {
                return $field; // This is line 198
            }
        
            $options = array();
            foreach ( $config['options'] as $option_key => $option_value ) {
                $selected = ( in_array( $option_key, $value, true ) ) ? 'selected="selected"' : '';
        
                $options[] = '<option value="' . esc_attr( $option_key ) . '" ' . $selected . '>' .
                esc_html( $option_value ) .
                '</option>';
            }
        
            $html = sprintf(
                '<select
                            multiple
                             class="%s"
                             name="%s"
                         >%s</select>',
                esc_attr( implode( ' ', isset( $config['input_class'] ) ? $config['input_class'] : array() ) ),
                esc_attr( $key ) . '[]',
                implode( '', $options )
            );
        
            return $html;
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search