Completed
Push — master ( 18b1b8...d3e350 )
by Claudio
07:42
created

wc-account-functions.php ➔ wc_get_account_menu_items()   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 39
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 7
eloc 25
c 4
b 0
f 0
nc 12
nop 0
dl 0
loc 39
rs 6.7272
1
<?php
2
/**
3
 * WooCommerce Account Functions
4
 *
5
 * Functions for account specific things.
6
 *
7
 * @author   WooThemes
8
 * @category Core
9
 * @package  WooCommerce/Functions
10
 * @version  2.6.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Returns the url to the lost password endpoint url.
19
 *
20
 * @access public
21
 * @param  string $default_url
22
 * @return string
23
 */
24
function wc_lostpassword_url( $default_url = '' ) {
25
	$wc_password_reset_url = wc_get_page_permalink( 'myaccount' );
26
27
	if ( false !== $wc_password_reset_url ) {
28
		return wc_get_endpoint_url( 'lost-password', '', $wc_password_reset_url );
29
	} else {
30
		return $default_url;
31
	}
32
}
33
34
add_filter( 'lostpassword_url', 'wc_lostpassword_url', 10, 1 );
35
36
/**
37
 * Get the link to the edit account details page.
38
 *
39
 * @return string
40
 */
41
function wc_customer_edit_account_url() {
42
	$edit_account_url = wc_get_endpoint_url( 'edit-account', '', wc_get_page_permalink( 'myaccount' ) );
43
44
	return apply_filters( 'woocommerce_customer_edit_account_url', $edit_account_url );
45
}
46
47
/**
48
 * Get the edit address slug translation.
49
 *
50
 * @param  string  $id   Address ID.
51
 * @param  bool    $flip Flip the array to make it possible to retrieve the values ​​from both sides.
52
 *
53
 * @return string        Address slug i18n.
54
 */
55
function wc_edit_address_i18n( $id, $flip = false ) {
56
	$slugs = apply_filters( 'woocommerce_edit_address_slugs', array(
57
		'billing'  => sanitize_title( _x( 'billing', 'edit-address-slug', 'woocommerce' ) ),
58
		'shipping' => sanitize_title( _x( 'shipping', 'edit-address-slug', 'woocommerce' ) )
59
	) );
60
61
	if ( $flip ) {
62
		$slugs = array_flip( $slugs );
63
	}
64
65
	if ( ! isset( $slugs[ $id ] ) ) {
66
		return $id;
67
	}
68
69
	return $slugs[ $id ];
70
}
71
72
/**
73
 * Get My Account menu items.
74
 *
75
 * @since 2.6.0
76
 * @return array
77
 */
78
function wc_get_account_menu_items() {
79
	$endpoints = array(
80
		'orders'          => get_option( 'woocommerce_myaccount_orders_endpoint', 'orders' ),
81
		'downloads'       => get_option( 'woocommerce_myaccount_downloads_endpoint', 'downloads' ),
82
		'edit-address'    => get_option( 'woocommerce_myaccount_edit_address_endpoint', 'edit-address' ),
83
		'payment-methods' => get_option( 'woocommerce_myaccount_payment_methods_endpoint', 'payment-methods' ),
84
		'edit-account'    => get_option( 'woocommerce_myaccount_edit_account_endpoint', 'edit-account' ),
85
		'customer-logout' => get_option( 'woocommerce_logout_endpoint', 'customer-logout' ),
86
	);
87
88
	$items = array(
89
		'dashboard'       => __( 'Dashboard', 'woocommerce' ),
90
		'orders'          => __( 'Orders', 'woocommerce' ),
91
		'downloads'       => __( 'Downloads', 'woocommerce' ),
92
		'edit-address'    => __( 'Addresses', 'woocommerce' ),
93
		'payment-methods' => __( 'Payment Methods', 'woocommerce' ),
94
		'edit-account'    => __( 'Account Details', 'woocommerce' ),
95
		'customer-logout' => __( 'Logout', 'woocommerce' ),
96
	);
97
98
	// Remove missing endpoints.
99
	foreach ( $endpoints as $endpoint_id => $endpoint ) {
100
		if ( empty( $endpoint ) ) {
101
			unset( $items[ $endpoint_id ] );
102
		}
103
	}
104
105
	// Check if payment gateways support add new payment methods.
106
	if ( isset( $items['payment-methods'] ) ) {
107
		foreach ( WC()->payment_gateways->get_available_payment_gateways() as $gateway ) {
108
			if ( $gateway->supports( 'add_payment_method' ) || $gateway->supports( 'tokenization' ) ) {
109
				unset( $items['payment-methods'] );
110
				break;
111
			}
112
		}
113
	}
114
115
	return apply_filters( 'woocommerce_account_menu_items', $items );
116
}
117
118
/**
119
 * Get account menu item classes.
120
 *
121
 * @since 2.6.0
122
 * @param string $endpoint
123
 * @return string
124
 */
125
function wc_get_account_menu_item_classes( $endpoint ) {
126
	global $wp;
127
128
	$classes = array(
129
		'woocommerce-MyAccount-navigation-link',
130
		'woocommerce-MyAccount-navigation-link--' . $endpoint,
131
	);
132
133
	// Set current item class.
134
	$current = isset( $wp->query_vars[ $endpoint ] );
135
	if ( 'dashboard' === $endpoint && ( isset( $wp->query_vars['page'] ) || empty( $wp->query_vars ) ) ) {
136
		$current = true; // Dashboard is not an endpoint, so needs a custom check.
137
	}
138
139
	if ( $current ) {
140
		$classes[] = 'is-active';
141
	}
142
143
	$classes = apply_filters( 'woocommerce_account_menu_item_classes', $classes, $endpoint );
144
145
	return implode( ' ', array_map( 'sanitize_html_class', $classes ) );
146
}
147
148
/**
149
 * Get account endpoint URL.
150
 *
151
 * @since 2.6.0
152
 * @param string $endpoint
153
 * @return string
154
 */
155
function wc_get_account_endpoint_url( $endpoint ) {
156
	if ( 'dashboard' === $endpoint ) {
157
		return wc_get_page_permalink( 'myaccount' );
158
	}
159
160
	return wc_get_endpoint_url( $endpoint );
161
}
162
163
/**
164
 * Get My Account > Orders columns.
165
 *
166
 * @since 2.6.0
167
 * @return array
168
 */
169
function wc_get_account_orders_columns() {
170
	$columns = apply_filters( 'woocommerce_account_orders_columns', array(
171
		'order-number'  => __( 'Order', 'woocommerce' ),
172
		'order-date'    => __( 'Date', 'woocommerce' ),
173
		'order-status'  => __( 'Status', 'woocommerce' ),
174
		'order-total'   => __( 'Total', 'woocommerce' ),
175
		'order-actions' => '&nbsp;',
176
	) );
177
178
	// Deprecated filter since 2.6.0.
179
	return apply_filters( 'woocommerce_my_account_my_orders_columns', $columns );
180
}
181
182
/**
183
 * Get My Account > Downloads columns.
184
 *
185
 * @since 2.6.0
186
 * @return array
187
 */
188
function wc_get_account_downloads_columns() {
189
	return apply_filters( 'woocommerce_account_downloads_columns', array(
190
		'download-file'      => __( 'File', 'woocommerce' ),
191
		'download-remaining' => __( 'Remaining', 'woocommerce' ),
192
		'download-expires'   => __( 'Expires', 'woocommerce' ),
193
		'download-actions'   => '&nbsp;',
194
	) );
195
}
196
197
/**
198
 * Get My Account > Payment methods columns.
199
 *
200
 * @since 2.6.0
201
 * @return array
202
 */
203
function wc_get_account_payment_methods_columns() {
204
	return apply_filters( 'woocommerce_account_payment_methods_columns', array(
205
		'method'  => __( 'Method', 'woocommerce' ),
206
		'expires' => __( 'Expires', 'woocommerce' ),
207
		'actions' => '&nbsp;',
208
	) );
209
}
210
211
/**
212
 * Get My Account > Payment methods types
213
 *
214
 * @since 2.6.0
215
 * @return array
216
 */
217
function wc_get_account_payment_methods_types() {
218
	return apply_filters( 'woocommerce_payment_methods_types', array(
219
		'cc'     => __( 'Credit Card', 'woocommerce' ),
220
		'echeck' => __( 'eCheck', 'woocommerce' ),
221
	) );
222
}
223
224
/**
225
 * Returns an array of a user's saved payments list for output on the account tab.
226
 *
227
 * @since  2.6
228
 * @param  array $list         List of payment methods passed from wc_get_customer_saved_methods_list()
229
 * @param  int   $customer_id  The customer to fetch payment methods for
230
 * @return array               Filtered list of customers payment methods
231
 */
232
function wc_get_account_saved_payment_methods_list( $list, $customer_id ) {
233
	$payment_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id );
234
	foreach ( $payment_tokens as $payment_token ) {
235
		$delete_url      = wc_get_endpoint_url( 'delete-payment-method', $payment_token->get_id() );
236
		$delete_url      = wp_nonce_url( $delete_url, 'delete-payment-method-' . $payment_token->get_id() );
237
		$set_default_url = wc_get_endpoint_url( 'set-default-payment-method', $payment_token->get_id() );
238
		$set_default_url = wp_nonce_url( $set_default_url, 'set-default-payment-method-' . $payment_token->get_id() );
239
240
		$type            = strtolower( $payment_token->get_type() );
241
		$list[ $type ][] = array(
242
			'method' => array(
243
				'gateway' => $payment_token->get_gateway_id(),
244
			),
245
			'expires'    => esc_html__( 'N/A', 'woocommerce' ),
246
			'is_default' => $payment_token->is_default(),
247
			'actions'    => array(
248
				'delete' => array(
249
					'url'  => $delete_url,
250
					'name' => esc_html__( 'Delete', 'woocommerce' ),
251
				),
252
			),
253
		);
254
		$key = key( array_slice( $list[ $type ], -1, 1, true ) );
255
256
		if ( ! $payment_token->is_default() ) {
257
			$list[ $type ][$key]['actions']['default'] = array(
258
				'url' => $set_default_url,
259
				'name' => esc_html__( 'Make Default', 'woocommerce' ),
260
			);
261
		}
262
263
		$list[ $type ][ $key ] = apply_filters( 'woocommerce_payment_methods_list_item', $list[ $type ][ $key ], $payment_token );
264
	}
265
	return $list;
266
}
267
268
add_filter( 'woocommerce_saved_payment_methods_list', 'wc_get_account_saved_payment_methods_list', 10, 2 );
269
270
/**
271
 * Controls the output for credit cards on the my account page.
272
 *
273
 * @since 2.6
274
 * @param  array             $item         Individual list item from woocommerce_saved_payment_methods_list
275
 * @param  WC_Payment_Token $payment_token The payment token associated with this method entry
276
 * @return array                           Filtered item
277
 */
278
function wc_get_account_saved_payment_methods_list_item_cc( $item, $payment_token ) {
279
	if ( 'cc' !== strtolower( $payment_token->get_type() ) ) {
280
		return $item;
281
	}
282
283
	$card_type               = $payment_token->get_card_type();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Payment_Token as the method get_card_type() does only exist in the following sub-classes of WC_Payment_Token: WC_Payment_Token_CC. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
284
	$item['method']['last4'] = $payment_token->get_last4();
285
	$item['method']['brand'] = ( ! empty( $card_type ) ? ucfirst( $card_type ) : esc_html__( 'Credit Card', 'woocommerce' ) );
286
	$item['expires']         = $payment_token->get_expiry_month() . '/' . substr( $payment_token->get_expiry_year(), -2 );
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Payment_Token as the method get_expiry_month() does only exist in the following sub-classes of WC_Payment_Token: WC_Payment_Token_CC. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
Bug introduced by
It seems like you code against a specific sub-type and not the parent class WC_Payment_Token as the method get_expiry_year() does only exist in the following sub-classes of WC_Payment_Token: WC_Payment_Token_CC. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
287
288
	return $item;
289
}
290
291
add_filter( 'woocommerce_payment_methods_list_item', 'wc_get_account_saved_payment_methods_list_item_cc', 10, 2 );
292
293
/**
294
 * Controls the output for eChecks on the my account page.
295
 *
296
 * @since 2.6
297
 * @param  array             $item         Individual list item from woocommerce_saved_payment_methods_list
298
 * @param  WC_Payment_Token $payment_token The payment token associated with this method entry
299
 * @return array                           Filtered item
300
 */
301
function wc_get_account_saved_payment_methods_list_item_echeck( $item, $payment_token ) {
302
	if ( 'echeck' !== strtolower( $payment_token->get_type() ) ) {
303
		return $item;
304
	}
305
306
	$item['method']['last4'] = $payment_token->get_last4();
307
	$item['method']['brand'] =  esc_html__( 'eCheck', 'woocommerce' );
308
309
	return $item;
310
}
311
312
add_filter( 'woocommerce_payment_methods_list_item', 'wc_get_account_saved_payment_methods_list_item_echeck', 10, 2 );
313