i use the woocommerce subscriptions plugin, i have a class class WC_Subscriptions_Cart {}, inside the function class is the following :
/**
* Display the recurring totals for items in the cart
*
* #since 2.0
*/
public static function display_recurring_totals() {
if ( self::cart_contains_subscription() ) {
// We only want shipping for recurring amounts, and they need to be calculated again here
self::$calculation_type = 'recurring_total';
$carts_with_multiple_payments = 0;
foreach ( WC()->cart->recurring_carts as $recurring_cart ) {
// Cart contains more than one payment
if ( 0 != $recurring_cart->next_payment_date ) {
$carts_with_multiple_payments++;
}
}
if ( apply_filters( 'woocommerce_subscriptions_display_recurring_totals', $carts_with_multiple_payments >= 1 ) ) {
wc_get_template(
'checkout/recurring-totals.php',
array(
'shipping_methods' => array(),
'recurring_carts' => WC()->cart->recurring_carts,
'carts_with_multiple_payments' => $carts_with_multiple_payments,
),
'',
WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' )
);
}
self::$calculation_type = 'none';
}
}
its action is as follows :
public static function init() {
add_action( 'woocommerce_cart_totals_after_order_total', __CLASS__ . '::display_recurring_totals' );
}
i want to disable this action, my code is not working :
function remove_my_class_action(){
remove_action( 'woocommerce_cart_totals_after_order_total', array( 'WC_Subscriptions_Cart', 'display_recurring_totals' ) );
} add_action( 'woocommerce_cart_totals_after_order_total', 'remove_my_class_action' );
how can i disable this action through the function.php file? i appreciate any reply from you.
after repeated attempts, i got the answer :
remove_action( 'woocommerce_cart_totals_after_order_total', array( 'WC_Subscriptions_Cart', 'display_recurring_totals' ), 10 );
Related
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
I would like to understand the sequence various classes are loaded in Wordpress.
There are many plugins available in Wordpress, then who will be loaded earlier than another.
Consider I would like to develop a plugin that will use some existing class of Woocommerce. Basically my custom plugin will extend some class of Woocommerce (for example : WC_Gateway_COD)
How I can ensure the existing class ‘WC_Gateway_COD’ is already defined & loaded before it execute the below statement ?
if (class_exists('WC_Gateway_COD')) {
class WC_my_custom_class extends WC_Gateway_COD {
…..
….
}
}
To make a custom gateway based on an existing WooCommerce payment method as COD, It's recommended to copy the source code from WC_Gateway_COD Class in a plugin (adapting the code for your needs) like:
defined( 'ABSPATH' ) or exit;
// Make sure WooCommerce is active
if ( ! in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
return;
}
add_filter( 'woocommerce_payment_gateways', 'wc_custom_add_to_gateways' );
function wc_custom_add_to_gateways( $gateways ) {
$gateways[] = 'WC_Gateway_COD2';
return $gateways;
}
add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'wc_gateway_custom_plugin_links' );
function wc_gateway_custom_plugin_links( $links ) {
$plugin_links = array(
'' . __( 'Configure', 'payment_cod2' ) . ''
);
return array_merge( $plugin_links, $links );
}
add_action( 'plugins_loaded', 'wc_gateway_cod2_init', 11 );
function wc_gateway_cod2_init() {
class WC_Gateway_COD2 extends WC_Payment_Gateway {
public $domain; // The text domain (optional)
/**
* Constructor for the gateway.
*/
public function __construct() {
$this->domain = 'payment_cod2'; // text domain name (for translations)
// Setup general properties.
$this->setup_properties();
// Load the settings.
$this->init_form_fields();
$this->init_settings();
// Get settings.
$this->title = $this->get_option( 'title' );
$this->description = $this->get_option( 'description' );
$this->instructions = $this->get_option( 'instructions' );
$this->enable_for_methods = $this->get_option( 'enable_for_methods', array() );
$this->enable_for_virtual = $this->get_option( 'enable_for_virtual', 'yes' ) === 'yes';
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
add_action( 'woocommerce_thankyou_' . $this->id, array( $this, 'thankyou_page' ) );
add_filter( 'woocommerce_payment_complete_order_status', array( $this, 'change_payment_complete_order_status' ), 10, 3 );
// Customer Emails.
add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
}
/**
* Setup general properties for the gateway.
*/
protected function setup_properties() {
$this->id = 'cod2';
$this->icon = apply_filters( 'woocommerce_cod2_icon', '' );
$this->method_title = __( 'Cash on delivery', 'woocommerce' );
$this->method_description = __( 'Have your customers pay with cash (or by other means) upon delivery.', 'woocommerce' );
$this->has_fields = false;
}
// and so on (the rest of the code)…
}
}
You can unset / remove original COD payment gateway changing the 1st function like:
add_filter( 'woocommerce_payment_gateways', 'wc_custom_add_to_gateways' );
function wc_custom_add_to_gateways( $gateways ) {
$gateways[] = 'WC_Gateway_COD2';
unset($gateways['WC_Gateway_COD']; // Remove COD gateway
return $gateways;
}
I am using the following code to use custom post type's custom field to use as a price field. So that I can add this field value in cart and make the payment.
Good news is that this custom post is successfully going into cart but the problem is that price value is Wrong.
Price should be $400 but it is displaying $51,376.
Here is the code:
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
// Put your plugin code here
add_action('woocommerce_loaded' , function (){
//Put your code here that needs any woocommerce class
//You can also Instantiate your main plugin file here
class WCCPT_Product_Data_Store_CPT extends WC_Product_Data_Store_CPT
{
/**
* Method to read a product from the database.
* #param WC_Product
*/
public function read(&$product)
{
$product->set_defaults();
if (!$product->get_id() || !($post_object = get_post($product->get_id())) || !in_array($post_object->post_type, array('refered_customer', 'product'))) { // change birds with your post type
throw new Exception(__('Invalid product.', 'woocommerce'));
}
$id = $product->get_id();
$product->set_props(array(
'name' => $post_object->post_title,
'slug' => $post_object->post_name,
'date_created' => 0 < $post_object->post_date_gmt ? wc_string_to_timestamp($post_object->post_date_gmt) : null,
'date_modified' => 0 < $post_object->post_modified_gmt ? wc_string_to_timestamp($post_object->post_modified_gmt) : null,
'status' => $post_object->post_status,
'description' => $post_object->post_content,
'short_description' => $post_object->post_excerpt,
'parent_id' => $post_object->post_parent,
'menu_order' => $post_object->menu_order,
'reviews_allowed' => 'open' === $post_object->comment_status,
));
$this->read_attributes($product);
$this->read_downloads($product);
$this->read_visibility($product);
$this->read_product_data($product);
$this->read_extra_data($product);
$product->set_object_read(true);
}
/**
* Get the product type based on product ID.
*
* #since 3.0.0
* #param int $product_id
* #return bool|string
*/
public function get_product_type($product_id)
{
$post_type = get_post_type($product_id);
if ('product_variation' === $post_type) {
return 'variation';
} elseif (in_array($post_type, array('refered_customer', 'product'))) { // change birds with your post type
return false;
} else {
return false;
}
}
}
});
}
add_filter( 'woocommerce_data_stores', 'woocommerce_data_stores' );
function woocommerce_data_stores ( $stores ) {
$stores['product'] = 'WCCPT_Product_Data_Store_CPT';
return $stores;
}
add_filter('woocommerce_product_get_price', 'woocommerce_product_get_price', 10, 2 );
function woocommerce_product_get_price( $invoice_price, $product ) {
if ($post->post->post_type === 'refered_customer') // change birds with your post type
$invoice_price = get_post_meta($post->id, "invoice_price", true);
return $invoice_price;
}
Updated - In your last hooked function to get the right price, you have some errors:
$post->post->post_type will not work as the $post object is not defined.
$post->id should be $post->ID, but it will not work as the $post object is not defined.
Instead you will use dedicated functions and methods: get_post_type() and $product->get_id().
So try this:
add_filter('woocommerce_product_get_price', 'woocommerce_product_get_price', 10, 2 );
function woocommerce_product_get_price( $price, $product ) {
// Change birds with your post type
if ( get_post_type( $product->get_id() ) === 'refered_customer' )
$price = get_post_meta( $product->get_id(), "invoice_price", true );
return $price;
}
Code goes in function.php file of your active child theme (or active theme). It should works now.
I am trying to add an include a template file located in my active child theme:
childtheme/woocommerce/myaccount/order-a-kit.php
The function use also echo "Hello World" which is displayed successfully, but not the included php template file.
I have tried those:
include($_SERVER['DOCUMENT_ROOT']."twentyseventeen-child/woocommerce/myaccount/order-a-kit.php");
include($get_stylesheet_directory_uri()."twentyseventeen-child/woocommerce/myaccount/order-a-kit.php");
include 'twentyseventeen-child/woocommerce/myaccount/order-a-kit.php';
The content of the order-a-kit.php is super simple, I am just trying to include that file:
<?php
?>
<div>
<p>
Look at me
</p>
</div>
This is my function.php section and everything is doing as it should except the include function towards the bottom:
add_filter( 'woocommerce_account_menu_items', 'add_my_menu_items', 99, 1 );
function add_my_menu_items( $items ) {
$my_items = array(
// endpoint => label
'order-a-kit' => __( 'Order A Kit', 'woocommerce'),
'orders' => __( 'Order History', 'my_plugin' ),
);
$my_items = array_slice( $items, 0, 1, true ) +
$my_items +
array_slice( $items, 1, count( $items ), true );
return $my_items;
}
//adding custom endpoint
function my_custom_endpoints() {
add_rewrite_endpoint( 'order-a-kit', EP_ROOT | EP_PAGES );
}
add_action( 'init', 'my_custom_endpoints' );
function my_custom_query_vars( $vars ) {
$vars[] = 'order-a-kit';
return $vars;
}
add_filter( 'query_vars', 'my_custom_query_vars', 0 );
function my_custom_flush_rewrite_rules() {
flush_rewrite_rules();
}
add_action( 'wp_loaded', 'my_custom_flush_rewrite_rules' );
//including custom endpoint
function my_custom_endpoint_content() {
include 'twentyseventeen-child/woocommerce/myaccount/order-a-kit.php';
echo '<p>Hello World!</p>';
}
add_action( 'woocommerce_account_order-a-kit_endpoint', 'my_custom_endpoint_content' );
?>
Any help is greatly appreciated.
As the "woocommerce" folder is inside your theme as the function.php file you just need to use:
include 'woocommerce/myaccount/order-a-kit.php';
See this related answer: WooCommerce: Adding custom template to customer account pages
Try this
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'woocommerce/myaccount/order-a-kit.php';
You can add this code to your theme's function.php:
class My_Custom_My_Account_Endpoint {
/**
* Custom endpoint name.
*
* #var string
*/
public static $endpoint = 'Your Desired Link';
/**
* Plugin actions.
*/
public function __construct() {
// Actions used to insert a new endpoint in the WordPress.
add_action( 'init', array( $this, 'add_endpoints' ) );
add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
// Change the My Accout page title.
add_filter( 'the_title', array( $this, 'endpoint_title' ) );
// Insering your new tab/page into the My Account page.
add_filter( 'woocommerce_account_menu_items', array( $this, 'new_menu_items' ) );
add_action( 'woocommerce_account_' . self::$endpoint . '_endpoint', array( $this, 'endpoint_content' ) );
}
/**
* Register new endpoint to use inside My Account page.
*
* #see https://developer.wordpress.org/reference/functions/add_rewrite_endpoint/
*/
public function add_endpoints() {
add_rewrite_endpoint( self::$endpoint, EP_ROOT | EP_PAGES );
}
/**
* Add new query var.
*
* #param array $vars
* #return array
*/
public function add_query_vars( $vars ) {
$vars[] = self::$endpoint;
return $vars;
}
/**
* Set endpoint title.
*
* #param string $title
* #return string
*/
public function endpoint_title( $title ) {
global $wp_query;
$is_endpoint = isset( $wp_query->query_vars[ self::$endpoint ] );
if ( $is_endpoint && ! is_admin() && is_main_query() && in_the_loop() && is_account_page() ) {
// New page title.
$title = __( 'Your Item Name', 'woocommerce' );
remove_filter( 'the_title', array( $this, 'endpoint_title' ) );
}
return $title;
}
/**
* Insert the new endpoint into the My Account menu.
*
* #param array $items
* #return array
*/
public function new_menu_items( $items ) {
// Remove the logout menu item.
$logout = $items['customer-logout'];
unset( $items['customer-logout'] );
// Insert your custom endpoint.
$items[ self::$endpoint ] = __( 'Your Item Name', 'woocommerce' );
// Insert back the logout item.
$items['customer-logout'] = $logout;
return $items;
}
/**
* Endpoint HTML content.
*/
public function endpoint_content() {
//example include('woocommerce/myaccount/Your-File.php');
include('Path-To-Your-File.php');
}
/**
* Plugin install action.
* Flush rewrite rules to make our custom endpoint available.
*/
public static function install() {
flush_rewrite_rules();
}
}
new My_Custom_My_Account_Endpoint();
// Flush rewrite rules on plugin activation.
register_activation_hook( __FILE__, array( 'My_Custom_My_Account_Endpoint', 'install' ) );
You have to simply set "Your Desired Link"x1 and "Your Item Name"x2 and "Path-To-Your-File.php"x1 in this source.
If you don't know where is your theme's function.php:
1.Log in to the WordPress Admin interface
2.In the left sidebar, hover over Appearances, then click Theme Editor
3.In the right sidebar, click functions.php
Every time you try and set a custom/action topic within webhooks (from WooCommerce > Settings > Webhooks) it would unset it as soon as you update your changes to the webhook. In other words, it will undo your custom topic and return it back to 'Select an option' for the topic dropdown.
Any help at all is appreciated. Thank you very much!
edit: In addition to my comment below, I've also attempted to create my own custom topic via the following filter woocommerce_webhook_topic_hooks, however, it doesn't show within the dropdown list as an option.
The below code runs from functions.php as with any WordPress hook..
Code
function custom_woocommerce_webhook_topics( $topic ) {
$topic['order.refunded'] = array(
'woocommerce_process_shop_order_meta',
'woocommerce_api_edit_order',
'woocommerce_order_edit_status',
'woocommerce_order_status_changed'
);
return $topic;
}
add_filter( 'woocommerce_webhook_topic_hooks', 'custom_woocommerce_webhook_topics', 10, 1 );
edit 2: Added more context
I was having the same issue. Selecting any of the built-in topics worked fine. But selection Action and entering any WooCommerce Subscription actions kept reverting. I had also tried creating a new custom topic in the same file (wp-content/plugins/woocommerce-subscriptions/includes/class-wcs-webhooks.php) that the built-in topics are created, mirroring 1:1 the code of one of the topics that 'stick' (e.g subscription.created) for a new 'subscription.paymentcomplete' topic. It appears in the drop down, but after saving the drop-down reverts to the default 'Selection an option...'.
//wp-content/plugins/woocommerce-subscriptions/includes/class-wcs-webhooks.php
public static function init() {
...
add_action( 'woocommerce_subscription_created_for_order', __CLASS__ . '::add_subscription_created_callback', 10, 2 );
add_action( 'woocommerce_subscription_payment_complete', __CLASS__ . '::add_subscription_payment_complete_callback', 10, );
...
}
public static function add_topics( $topic_hooks, $webhook ) {
if ( 'subscription' == $webhook->get_resource() ) {
$topic_hooks = apply_filters( 'woocommerce_subscriptions_webhook_topics', array(
'subscription.created' => array(
'wcs_api_subscription_created',
'wcs_webhook_subscription_created',
'woocommerce_process_shop_subscription_meta',
),
'subscription.paymentcomplete' => array(
'wcs_webhook_subscription_payment_complete'
'woocommerce_process_shop_subscription_meta',
),
...
), $webhook );
}
return $topic_hooks;
}
public static function add_topics_admin_menu( $topics ) {
$front_end_topics = array(
'subscription.created' => __( ' Subscription Created', 'woocommerce-subscriptions' ),
'subscription.paymentcomplete' => __( ' Subscription Payment Complete', 'woocommerce-subscriptions' ),
...
);
return array_merge( $topics, $front_end_topics );
}
public static function add_subscription_created_callback( $order, $subscription ) {
do_action( 'wcs_webhook_subscription_created', $subscription->id );
}
public static function add_subscription_payment_complete_callback( $order, $subscription ) {
do_action( 'wcs_webhook_subscription_payment_complete', $subscription->id );
}
The solution was:
add_filter( 'woocommerce_valid_webhook_events', __CLASS__ . '::add_event', 10, 1 );
public static function add_event( $events) {
$events[] = 'paymentcomplete';
return $events;
}