Completed
Push — master ( fc6097...930cc3 )
by Mike
08:01
created

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

Complexity

Conditions 6
Paths 12

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 6
eloc 20
c 3
b 0
f 0
nc 12
nop 0
dl 0
loc 33
rs 8.439
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
	$items = array(
80
		'dashboard'       => __( 'Dashboard', 'woocommerce' ),
81
		'orders'          => __( 'Orders', 'woocommerce' ),
82
		'downloads'       => __( 'Downloads', 'woocommerce' ),
83
		'edit-address'    => __( 'Addresses', 'woocommerce' ),
84
		'payment-methods' => __( 'Payment Methods', 'woocommerce' ),
85
		'edit-account'    => __( 'Account Details', 'woocommerce' ),
86
		'customer-logout' => __( 'Logout', 'woocommerce' ),
87
	);
88
89
	// Remove downloads if no downloadable products exist.
90
	$downloads = wc_get_customer_download_permissions( get_current_user_id() );
91
92
	if ( ! sizeof( $downloads ) ) {
93
		unset( $items['downloads'] );
94
	}
95
96
	// Check if payment gateways support add new payment methods.
97
	$support_payment_methods = false;
98
	foreach ( WC()->payment_gateways->get_available_payment_gateways() as $gateway ) {
99
		if ( $gateway->supports( 'add_payment_method' ) || $gateway->supports( 'tokenization' ) ) {
100
			$support_payment_methods = true;
101
			break;
102
		}
103
	}
104
105
	if ( ! $support_payment_methods ) {
106
		unset( $items['payment-methods'] );
107
	}
108
109
	return apply_filters( 'woocommerce_account_menu_items', $items );
110
}
111
112
/**
113
 * Get account menu item classes.
114
 *
115
 * @since 2.6.0
116
 * @param string $endpoint
117
 * @return string
118
 */
119
function wc_get_account_menu_item_classes( $endpoint ) {
120
	global $wp;
121
122
	$classes = array(
123
		'woocommerce-MyAccount-navigation-link',
124
		'woocommerce-MyAccount-navigation-link--' . $endpoint,
125
	);
126
127
	// Set current item class.
128
	$current = isset( $wp->query_vars[ $endpoint ] );
129
	if ( 'dashboard' === $endpoint && ( isset( $wp->query_vars['page'] ) || empty( $wp->query_vars ) ) ) {
130
		$current = true; // Dashboard is not an endpoint, so needs a custom check.
131
	}
132
133
	if ( $current ) {
134
		$classes[] = 'is-active';
135
	}
136
137
	$classes = apply_filters( 'woocommerce_account_menu_item_classes', $classes, $endpoint );
138
139
	return implode( ' ', array_map( 'sanitize_html_class', $classes ) );
140
}
141
142
/**
143
 * Get account endpoint URL.
144
 *
145
 * @since 2.6.0
146
 * @param string $endpoint
147
 * @return string
148
 */
149
function wc_get_account_endpoint_url( $endpoint ) {
150
	if ( 'dashboard' === $endpoint ) {
151
		return wc_get_page_permalink( 'myaccount' );
152
	}
153
154
	return wc_get_endpoint_url( $endpoint );
155
}
156
157
/**
158
 * Get My Account > Orders columns.
159
 *
160
 * @since 2.6.0
161
 * @return array
162
 */
163
function wc_get_account_orders_columns() {
164
	$columns = apply_filters( 'woocommerce_account_orders_columns', array(
165
		'order-number'  => __( 'Order', 'woocommerce' ),
166
		'order-date'    => __( 'Date', 'woocommerce' ),
167
		'order-status'  => __( 'Status', 'woocommerce' ),
168
		'order-total'   => __( 'Total', 'woocommerce' ),
169
		'order-actions' => '&nbsp;',
170
	) );
171
172
	// Deprecated filter since 2.6.0.
173
	return apply_filters( 'woocommerce_my_account_my_orders_columns', $columns );
174
}
175
176
/**
177
 * Get My Account > Downloads columns.
178
 *
179
 * @since 2.6.0
180
 * @return array
181
 */
182
function wc_get_account_downloads_columns() {
183
	return apply_filters( 'woocommerce_account_downloads_columns', array(
184
		'download-file'      => __( 'File', 'woocommerce' ),
185
		'download-remaining' => __( 'Remaining', 'woocommerce' ),
186
		'download-expires'   => __( 'Expires', 'woocommerce' ),
187
		'download-actions'   => '&nbsp;',
188
	) );
189
}
190
191
/**
192
 * Get My Account > Payment methods columns.
193
 *
194
 * @since 2.6.0
195
 * @return array
196
 */
197
function wc_get_account_payment_methods_columns() {
198
	return apply_filters( 'woocommerce_account_payment_methods_columns', array(
199
		'method'  => __( 'Method', 'woocommerce' ),
200
		'expires' => __( 'Expires', 'woocommerce' ),
201
		'actions' => '&nbsp;',
202
	) );
203
}
204
205
/**
206
 * Get My Account > Payment methods types
207
 *
208
 * @since 2.6.0
209
 * @return array
210
 */
211
function wc_get_account_payment_methods_types() {
212
	return apply_filters( 'woocommerce_payment_methods_types', array(
213
		'cc'     => __( 'Credit Card', 'woocommerce' ),
214
		'echeck' => __( 'eCheck', 'woocommerce' ),
215
	) );
216
}
217
218
/**
219
 * Returns an array of a user's saved payments list for output on the account tab.
220
 *
221
 * @since  2.6
222
 * @param  array $list         List of payment methods passed from wc_get_customer_saved_methods_list()
223
 * @param  int   $customer_id  The customer to fetch payment methods for
224
 * @return array               Filtered list of customers payment methods
225
 */
226
function wc_get_account_saved_payment_methods_list( $list, $customer_id ) {
227
	$payment_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id );
228
	foreach ( $payment_tokens as $payment_token ) {
229
		$delete_url      = wc_get_endpoint_url( 'delete-payment-method', $payment_token->get_id() );
230
		$delete_url      = wp_nonce_url( $delete_url, 'delete-payment-method-' . $payment_token->get_id() );
231
		$set_default_url = wc_get_endpoint_url( 'set-default-payment-method', $payment_token->get_id() );
232
		$set_default_url = wp_nonce_url( $set_default_url, 'set-default-payment-method-' . $payment_token->get_id() );
233
234
		$type            = strtolower( $payment_token->get_type() );
235
		$list[ $type ][] = array(
236
			'method' => array(
237
				'gateway' => $payment_token->get_gateway_id(),
238
			),
239
			'expires'    => esc_html__( 'N/A', 'woocommerce' ),
240
			'is_default' => $payment_token->is_default(),
241
			'actions'    => array(
242
				'delete' => array(
243
					'url'  => $delete_url,
244
					'name' => esc_html__( 'Delete', 'woocommerce' ),
245
				),
246
			),
247
		);
248
		$key = key( array_slice( $list[ $type ], -1, 1, true ) );
249
250
		if ( ! $payment_token->is_default() ) {
251
			$list[ $type ][$key]['actions']['default'] = array(
252
				'url' => $set_default_url,
253
				'name' => esc_html__( 'Make Default', 'woocommerce' ),
254
			);
255
		}
256
257
		$list[ $type ][ $key ] = apply_filters( 'woocommerce_payment_methods_list_item', $list[ $type ][ $key ], $payment_token );
258
	}
259
	return $list;
260
}
261
262
add_filter( 'woocommerce_saved_payment_methods_list', 'wc_get_account_saved_payment_methods_list', 10, 2 );
263
264
/**
265
 * Controls the output for credit cards on the my account page.
266
 *
267
 * @since 2.6
268
 * @param  array             $item         Individual list item from woocommerce_saved_payment_methods_list
269
 * @param  WC_Payment_Token $payment_token The payment token associated with this method entry
270
 * @return array                           Filtered item
271
 */
272
function wc_get_account_saved_payment_methods_list_item_cc( $item, $payment_token ) {
273
	if ( 'cc' !== strtolower( $payment_token->get_type() ) ) {
274
		return $item;
275
	}
276
277
	$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...
278
	$item['method']['last4'] = $payment_token->get_last4();
279
	$item['method']['brand'] = ( ! empty( $card_type ) ? ucfirst( $card_type ) : esc_html__( 'Credit Card', 'woocommerce' ) );
280
	$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...
281
282
	return $item;
283
}
284
285
add_filter( 'woocommerce_payment_methods_list_item', 'wc_get_account_saved_payment_methods_list_item_cc', 10, 2 );
286
287
/**
288
 * Controls the output for eChecks on the my account page.
289
 *
290
 * @since 2.6
291
 * @param  array             $item         Individual list item from woocommerce_saved_payment_methods_list
292
 * @param  WC_Payment_Token $payment_token The payment token associated with this method entry
293
 * @return array                           Filtered item
294
 */
295
function wc_get_account_saved_payment_methods_list_item_echeck( $item, $payment_token ) {
296
	if ( 'echeck' !== strtolower( $payment_token->get_type() ) ) {
297
		return $item;
298
	}
299
300
	$item['method']['last4'] = $payment_token->get_last4();
301
	$item['method']['brand'] =  esc_html__( 'eCheck', 'woocommerce' );
302
303
	return $item;
304
}
305
306
add_filter( 'woocommerce_payment_methods_list_item', 'wc_get_account_saved_payment_methods_list_item_echeck', 10, 2 );
307