Customers and the My account area
A customer is an ordinary WordPress user with the customer role. Their addresses and purchase history are available through the WC_Customer object, and the personal area is on the My account page (/my-account/). You can add your own tab there — for example, a list of the customer's reviews.
Where to write the code
Create the includes/account.php file and include it in acme-shop.php.
Reading a customer
// wp-content/plugins/acme-shop/includes/account.php
add_action('woocommerce_account_dashboard', function () {
$customer = new WC_Customer(get_current_user_id());
printf(
'<p>Orders: %d, total %s. Shipping city: %s.</p>',
$customer->get_order_count(),
wc_price($customer->get_total_spent()),
esc_html($customer->get_shipping_city() ?: 'not set')
);
});The constructor takes a user ID. The woocommerce_account_dashboard hook prints a block on the first tab of the account — log in and open /my-account/ to see the line.
Properties
| Method | What it returns |
|---|---|
get_email() | The email address |
get_first_name(), get_last_name() | The first and last name |
get_billing_phone() | The phone |
get_billing(), get_shipping() | An address as an array |
get_order_count() | The number of orders |
get_total_spent() | The total of paid orders |
get_is_paying_customer() | Whether there was at least one paid order |
Addresses are stored in user meta — the wp_usermeta table, keys like billing_city and shipping_postcode.
Changing and your own data
// wp-content/plugins/acme-shop/scripts/update-customer.php
$customer = new WC_Customer(7);
$customer->set_billing_phone('+49 30 1234567');
$customer->update_meta_data('acme_birthday', '1990-05-14');
$customer->save();
echo $customer->get_meta('acme_birthday') . PHP_EOL;The rule is the same: set_..., then save(). Run the file with wp eval-file — it prints the saved date. The current customer on the site is WC()->customer: the object exists for a guest too, whose ID is 0.
A tab in the account
A tab consists of three parts: an address, a menu item and content.
// wp-content/plugins/acme-shop/includes/account.php
add_action('init', function () {
add_rewrite_endpoint('my-reviews', EP_ROOT | EP_PAGES);
});
add_filter('woocommerce_account_menu_items', function (array $items): array {
$logout = $items['customer-logout'];
unset($items['customer-logout']);
$items['my-reviews'] = 'My reviews';
$items['customer-logout'] = $logout;
return $items;
});The first function registers the /my-account/my-reviews/ address. The filter adds a menu item before Log out. After adding the code open Settings → Permalinks and press Save Changes — otherwise the new address returns 404.
The tab content
// wp-content/plugins/acme-shop/includes/account.php
add_action('woocommerce_account_my-reviews_endpoint', function () {
$reviews = get_comments([
'user_id' => get_current_user_id(),
'post_type' => 'product',
'status' => 'approve',
]);
if (!$reviews) {
echo '<p>You have not left any reviews yet.</p>';
return;
}
echo '<ul>';
foreach ($reviews as $review) {
printf(
'<li><a href="%s">%s</a>: %s</li>',
esc_url(get_permalink($review->comment_post_ID)),
esc_html(get_the_title($review->comment_post_ID)),
esc_html($review->comment_content)
);
}
echo '</ul>';
});The hook name is assembled from the tab address: woocommerce_account_ + my-reviews + _endpoint. A product review is a WordPress comment on a post of the product type. Leave a review for the mug and open the My reviews tab: a link to the product and the text appear in the list.
Removing a tab
add_filter('woocommerce_account_menu_items', function (array $items): array {
unset($items['downloads']);
return $items;
});The Downloads tab is not needed in a shop without digital products.
Common mistake
The tab was added, the menu item is visible, but the page opens with a 404 error. WordPress keeps address rules in the database and does not know about the new one. Re-save permalinks in the admin panel — once after adding add_rewrite_endpoint().