Checking user role on a hooked function breaking website in WooCommerce - php

I am trying to add a tab to the My Account page if a specific user exists.
I created a check_user_role function that checks if a specific role exists.
If the premium_member role exists an extra tab should be added to the My Account page.
Right now when I add the check_user_role function it breaks my website.
Everything is in the functions.php file
function check_user_role($roles, $user_id = null) {
if ($user_id) $user = get_userdata($user_id);
else $user = wp_get_current_user();
if (empty($user)) return false;
foreach ($user->roles as $role) {
if (in_array($role, $roles)) {
return true;
}
}
return false;
}
// ------------------
// 1. Register new endpoint (URL) for My Account page
// Note: Re-save Permalinks or it will give 404 error
function vehicle_intake_form_endpoint() {
add_rewrite_endpoint( 'vehicle-intake-form', EP_ROOT | EP_PAGES );
}
add_action( 'init', 'vehicle_intake_form_endpoint' );
// ------------------
// 2. Add new query var
function vehicle_intake_form_query_vars( $vars ) {
$vars[] = 'vehicle-intake-form';
return $vars;
}
add_filter( 'query_vars', 'vehicle_intake_form_query_vars', 0 );
// ------------------
// 3. Insert the new endpoint into the My Account menu
if(check_user_role(array('premium_member'))) {
function vehicle_intake_form_link_my_account( $items ) {
$items['vehicle-intake-form'] = 'Vehicle Intake Form';
return $items;
}
add_filter( 'woocommerce_account_menu_items', 'vehicle_intake_form_link_my_account' );
}
// ------------------
// 4. Add content to the new tab
function vehicle_intake_form_content() {
echo '<h3>Premium WooCommerce Support</h3><p>Welcome to the WooCommerce support area. As a premium customer, you can submit a ticket should you have any WooCommerce issues with your website, snippets or customization. <i>Please contact your theme/plugin developer for theme/plugin-related support.</i></p>';
//echo do_shortcode( ' /* your shortcode here */ ' );
}
add_action( 'woocommerce_account_vehicle-intake-form_endpoint', 'vehicle_intake_form_content' );

Your If statement needs to be inside the function, never outside it.
You can use current_user_can() function, but inside your hooked function like:
add_filter( 'woocommerce_account_menu_items', 'vehicle_intake_form_link_my_account' );
function vehicle_intake_form_link_my_account( $items ) {
if( current_user_can('premium_member') ) {
$items['vehicle-intake-form'] = __('Vehicle Intake Form');
}
return $items;
}
Or use check_user_role() revisited function to be used inside your hooked function like:
function check_user_role( $roles, $user_id = null ) {
$user = $user_id ? new WP_User( $user_id ) : wp_get_current_user();
if ( is_a($user, 'WP_User') && count( array_intersect($roles, $user->roles) ) > 0 ) {
return true;
}
return false;
}
add_filter( 'woocommerce_account_menu_items', 'vehicle_intake_form_link_my_account' );
function vehicle_intake_form_link_my_account( $items ) {
if( check_user_role( array('premium_member') ) ) {
$items['vehicle-intake-form'] = __('Vehicle Intake Form');
}
return $items;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.

Related

Add custom my account menu item based on user role in WooCommerce 3+

I am using WordPress and WooCommerce and I have followed this article https://rudrastyh.com/woocommerce/my-account-menu.html to add new menu items in WooCommerce my account menus.
This is my working code.
function getUserRolesByUserId( $id ) {
if ( !is_user_logged_in() ) { return false; }
$oUser = get_user_by( 'id', $id );
$aUser = get_object_vars( $oUser );
$sRoles = $aUser['roles'];
return $sRoles;
}
function createMenuBasedonUserRole($userId)
{
$userRoleIds = getUserRolesByUserId(get_current_user_id());
$urlMenuData = [];
if(!empty($userRoleIds) && in_array('mindesk_var_account',$userRoleIds)) {
$urlMenuData = [
'pageName' => "Clients",
"pageLink" => "clients"
];
} else if(!empty($userRoleIds) && in_array('mindesk_owner_account',$userRoleIds)) {
$urlMenuData = [
'pageName' => "Children",
"pageLink" => "children"
];
}
return $urlMenuData;
}
/*
* Step 1. Add Link (Tab) to My Account menu
*/
add_filter ( 'woocommerce_account_menu_items', 'mindesk_clients_children_link', 40 );
function mindesk_clients_children_link( $menu_links ){
$urlData = createMenuBasedonUserRole(get_current_user_id());
if(!empty($urlData)){
$menu_links = array_slice( $menu_links, 0, 5, true ) + array( $urlData['pageLink'] => $urlData['pageName'] ) + array_slice( $menu_links, 5, NULL, true );
}
return $menu_links;
}
/*
* Step 2. Register Permalink Endpoint
*/
add_action( 'init', 'mindesk_add_menu_endpoint' );
function mindesk_add_menu_endpoint() {
add_rewrite_endpoint( 'clients', EP_PAGES );
add_rewrite_endpoint( 'children', EP_PAGES );
}
/*
* Step 3. Content for the new page in My Account, woocommerce_account_{ENDPOINT NAME}_endpoint
*/
add_action( 'woocommerce_account_clients_endpoint', 'mindesk_clients_my_account_endpoint_content' );
function mindesk_clients_my_account_endpoint_content() {
require_once(get_template_directory() . '/myaccount/clients.php') ;
}
add_action( 'woocommerce_account_children_endpoint', 'mindesk_children_my_account_endpoint_content' );
function mindesk_children_my_account_endpoint_content() {
require_once(get_template_directory() . '/myaccount/children.php') ;
}
/* Step 4
*/
// Go to Settings > Permalinks and just push "Save Changes" button.
And this is my how my new menu called as "Clients" showing.
As you can see above, I have added new menu and executing the page and based on user role mindesk_var_account I need to show clients and mindesk_owner_account I need to show children.
I have created these 2 php pages at /wp-content/themes/twentytwentyone/myaccount and its working fine.
However, I want to use wp_die or something if user with another role try to access one of the page which they are not allowed to.
So for example if logged in user has mindesk_var_account role then if they try to go to http://localhost/wordpress/my-account/clients/ then i need to use wp_die() to not execute it.
I tried to use wp_die inside these new 2 pages but then menus and other things executed. I just want something like this.
I tried to use following code...
add_action( 'template_redirect', 'my_account_redirect' );
function my_account_redirect() {
if( is_page( 'my-account' ) ) {
wp_die('fg');
}
}
But then its checking for all my-account pages .. and I want it to be checked only for inner pages like client or children.
Can someone guide me how can I achieve this what should I do from here on.
Thanks
There are still some little mistakes in your code, some missing things and since WooCommerce 3 there are some related changes within step 2 for My account endpoints. Some things can be simplified too.
To avoid non allowed user roles to access to some prohibited section(s) or endpoint(s) you can use a custom function hooked in template_redirect hook that will redirect user to an allowed section.
Here is the complete code:
// Custom function that get My account menu item data based on user roles
function get_menu_item_by_user_role() {
$user_roles = wp_get_current_user()->roles;
if ( ! empty($user_roles) ) {
$menu_item = [];
// if ( in_array('mindesk_var_account', $user_roles) ) {
if ( in_array( 'mindesk_var_account', $user_roles ) ) {
$menu_item = [ 'clients' => __( "Clients", "woocommerce" ) ];
}
elseif( in_array( 'mindesk_owner_account', $user_roles ) ) {
$menu_item = [ 'children' => __( "Children", "woocommerce" ) ];
}
}
return $menu_item;
}
// Step 1 - Add Link (Tab) to My Account menu
add_filter ( 'woocommerce_account_menu_items', 'add_mindesk_custom_menu_items', 40 );
function add_mindesk_custom_menu_items( $menu_items ){
$new_item = get_menu_item_by_user_role();
if ( ! empty($new_item) ) {
$menu_items = array_slice( $menu_items, 0, 5, true ) + $new_item + array_slice( $menu_items, 5, null, true );
}
return $menu_items;
}
// Step 2 - Enable endpoint (and endpoint permalink) - Since WooCommerce 3
add_filter( 'woocommerce_get_query_vars', 'add_mindesk_menu_item_endpoint' );
function add_mindesk_menu_item_endpoint( $query_vars ) {
$query_vars['clients'] = 'clients';
$query_vars['children'] = 'children';
return $query_vars;
}
// Step 3. Content for the new page in My Account, woocommerce_account_{ENDPOINT NAME}_endpoint
add_action( 'woocommerce_account_clients_endpoint', 'add_mindesk_account_clients_endpoint_content' );
function add_mindesk_account_clients_endpoint_content() {
require_once(get_template_directory() . '/myaccount/clients.php') ;
}
add_action( 'woocommerce_account_children_endpoint', 'add_mindesk_account_children_endpoint_content' );
function add_mindesk_account_children_endpoint_content() {
require_once(get_template_directory() . '/myaccount/children.php') ;
}
// Step 4. Endpoint page title
add_filter( 'woocommerce_endpoint_clients_title', 'set_mindesk_account_clients_endpoint_title', 10, 2 );
function set_mindesk_account_clients_endpoint_title( $title, $endpoint ) {
$title = __("Clients", "woocommerce" );
return $title;
}
add_filter( 'woocommerce_endpoint_children_title', 'set_mindesk_account_children_endpoint_title', 10, 2 );
function set_mindesk_account_children_endpoint_title( $title, $endpoint ) {
$title = __( "Children", "woocommerce" );
return $title;
}
// Step 5. Redirect if not allowed user role
add_action( 'template_redirect', 'redirect_mindesk_account_dashboard' );
function redirect_mindesk_account_dashboard() {
if ( is_account_page() ) {
global $wp;
$item_key = array_keys(get_menu_item_by_user_role());
$page_url = get_permalink( get_option('woocommerce_myaccount_page_id') );
if ( empty($item_key) && ( isset($wp->query_vars['children']) || isset($wp->query_vars['clients']) ) ) {
wp_safe_redirect( get_permalink($page_id) );
exit();
}
elseif ( 'clients' == reset($item_key) && isset($wp->query_vars['children']) ) {
wp_safe_redirect( get_permalink($page_id) . 'clients/' );
exit();
}
elseif ( 'children' == reset($item_key) && isset($wp->query_vars['clients']) ) {
wp_safe_redirect( get_permalink($page_id) . 'children/' );
exit();
}
}
}
// Step 6. FLush rewrite rules:
// Go to Settings > Permalinks and click on "Save Changes".
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
related: WooCommerce My Account custom endpoint menu item

Get current user id inside shortcode return ever 0

I'm trying to customize a shortcode put inside a custom plugin, but I can't get the user id, it always returns me 0.
It might also be okay to understand the role with current_user_can, but any information is always empty.
Here the code:
add_action( 'plugins_loaded', 'check_current_user' );
function check_current_user() {
// Your CODE with user data
global $current_user;
$current_user = wp_get_current_user();
return $current_user->ID;
}
function appp_hide_content_shortcode( $atts, $content = '' ) {
if( class_exists('AppPresser') && AppPresser::is_app() )
return check_current_user();
else
return $content;
}
add_shortcode('appp_hide_content', 'appp_hide_content_shortcode');
Please try this
/**
* Hide content on app.
*
* Use this shortcode to hide content when viewed using the app.
*
* Use:
* [appp_hide_content]This content will not appear on the app.[/appp_hide_content]
*/
function appp_hide_content_shortcode( $atts, $content = '' ) {
ob_start();
//GET CURRENT USER ID
global $current_user;
$current_user = wp_get_current_user();
echo $current_user->ID;
if (current_user_can('free')){
if( class_exists('AppPresser') && AppPresser::is_app() )
echo '';
else
echo $content;
}
$sc_html = ob_get_contents();
ob_end_clean();
return $sc_html;
}
add_shortcode('appp_hide_content', 'appp_hide_content_shortcode');
You need to check the user after the user is loaded. I would hook to init. You can't call the pluggable functions directly in a plugin without delaying the execution. The simpler solution to your problem would be to include your shortcode in your theme's functions.php, rather than in a plugin. But below will execute.
add_action( 'init', 'check_current_user' , 999);
function check_current_user() {
// This returns current user id
return get_current_user_id();
}
function appp_hide_content_shortcode( $atts, $content = '' ) {
if( class_exists('AppPresser') && AppPresser::is_app() ){
// This is only returning an integer here.
return check_current_user();
} else {
return $content;
}
}
add_shortcode('appp_hide_content', 'appp_hide_content_shortcode');

Display a custom field next in the Woocommerce admin panel

I'm at wits end with this now and could really use a hand.
I've added a form on the front end that asks the customer to register with their IRL user account number, I've managed to get that to store in the back end as "morello_account_number". Now I want to echo that account number on the order page in Woocommerce so that I can process orders easier without searching the customers username etc manually. I'm not really a PHP programmer, but here's my code so far:
add_filter('manage_edit-shop_order_columns', 'morello_account_number_column' );
function morello_account_number_column( $order_columns ) {
$order_columns['morello_account_number'] = "Morello Account Number";
return $order_columns;
}
add_action( 'manage_shop_order_posts_custom_column' , 'morello_placeholder' );
function morello_placeholder( $colname ) {
global $the_order; // the global order object
if( $colname == 'morello_account_number' ) {
$morello_account_number = $order->get_morello_account_number();
echo morello_account_number;
}
}
Apologies if this is super trivial - still learning. And thanks so much in advance.
Assuming you've used update_post_meta before in your previous code?
Then you could apply the following
/**
* Add columns
*/
function morello_account_number_column( $columns ) {
$columns['morello_account_number'] = "Morello Account Number";
return $columns;
}
add_filter('manage_edit-shop_order_columns', 'morello_account_number_column', 10, 1 );
/**
* Populate columns
*/
function morello_placeholder( $column, $post_id ) {
if( $column == 'morello_account_number' ) {
// https://developer.wordpress.org/reference/functions/get_post_meta/
$m_a_n = get_post_meta( $post_id, 'morello_account_number', true );
// Value is found
if ( !empty($m_a_n) ) {
echo $m_a_n;
} else {
echo 'something else';
}
}
}
add_filter( 'manage_shop_order_posts_custom_column', 'morello_placeholder', 10, 2 );

Unable to Override WooCommerce Checkout Fields

I've created a custom WooCommerce checkout field with Woothemes Checkout Field Editor labeled "po_number". I would like the PO Number checkout field to only display for the user role "distributor".
So far I've been unsuccessful in overriding the checkout fields. I'm using Wordpress 4.5.1 / Woocommerce 2.5.5. Here's the code I've placed in my child theme's functions.php. I've also tested to make sure it is not a theme conflict.
Any help is greatly appreciated.
This is my code:
function custom_override_checkout_fields( $fields ) {
if ( ! current_user_can( 'distributor' ) && isset( $fields['billing']['po_number'] ) ) {
unset($fields['billing']['po_number']);
}
return $fields;
}
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
The current_user_can() function is related to capabilities of the user roles, but not to detect the user roles themselves. For that reason is not working in your code.
You need to set a conditional function for this purpose (user roles):
function is_user_role( $role, $user_id = null ) {
if ( is_numeric( $user_id ) ) {
$user = get_userdata( $user_id );
} else {
$user = wp_get_current_user();
}
if ( empty( $user ) ) {
return false;
}
if ( in_array( $role, (array) $user->roles ) == 1) {
return true;
} else {
return false;
}
}
Then in your code you can use that function:
function custom_override_checkout_fields( $fields ) {
if ( !is_user_role( 'distributor' ) && isset( $fields['billing']['po_number'] ) ) {
unset($fields['billing']['po_number']);
}
return $fields;
}
add_filter( 'woocommerce_checkout_fields', 'custom_override_checkout_fields' );
This should work in your code.

How save product id of 1st item added to cart in woocommerce for a visitor in empty cart page?

I am trying to display the product id which is added to cart at first in empty cart page(cart-empty.php). Can anyone please help me with any solution.
Here is my code I have tried for cart-totals.php page..which save both product slug and its parent slug which is added at last to the cart.
$items = $woocommerce->cart->get_cart();
foreach($_SESSION['items'] as $item => $values) {
$_product = $values['data']->post;
$cartproductid = $_product->ID;
}
$product_cats = wp_get_post_terms( $cartproductid, 'product_cat' );
$url=$product_cats[0]->slug;
$parenturl=$product_cats[0]->parent;
$terms = get_the_terms($cartproductid, "product_cat");
$cat = get_term_by("id", $parenturl, "product_cat");
$newurl = $cat->slug;
This code displays a message whenever a user removes an item from their cart. It may not be exactly what you want but it gives you something to start off with. Add this code to your theme functions.php or custom plugin code:
function this_function( $title , $cart_item){
wc_add_notice( 'Visit deleted product ' . $title . '' );
return $title;
}
add_filter( 'woocommerce_cart_item_removed_title', 'this_function', 10, 2 );
EDIT - More accurate solution: This code displays a message on the empty cart page with a link to the last deleted product. It works for users who are logged in. If you want the code to work for non-logged in visitors you'll need to modify this to use cookies.
class empty_cart
{
public $last_product;
protected static $_instance = null;
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
function __construct()
{
add_filter( 'woocommerce_cart_item_removed_title', array($this, 'product_removed'), 10, 2 );
add_action( 'woocommerce_cart_is_empty', array($this, 'cart_is_empty'));
}
function product_removed( $title , $cart_item){
update_user_meta( get_current_user_id(), 'last_removed_product', $cart_item['product_id']);
$this->last_product = $cart_item['product_id'];
return $title;
}
function cart_is_empty(){
$last_product = $this->get_last_product();
echo 'Visit deleted product ' . get_the_title( $last_product ) . '';
}
function get_last_product(){
if( isset($this->last_product) )
return $this->last_product;
else
return get_user_meta( get_current_user_id(), 'last_removed_product',true );
}
}
function empty_cart() {
return empty_cart::instance();
}
empty_cart();

Categories