How to check that we are not in a Woocommerce endpoint - woocommerce

since WooCommerce 2.1 pages such as order-received has been removed and replaced with WC endpoints. My checkout page had a custom page template (page-checkout.php) and now all checkout endpoints are also using this custom page template.
I need to modify my header and footer only when my customers are in the /checkout/ page, but I want to show different content when they are in a checkout endpoints. I have found this conditional:
if(is_wc_endpoint_url("order-received")) echo "yes";
It works when we are in the "order-received" checkout endpoint. But I am looking for a conditional logic that tells me when we are not in an endpoint, something like:
if(!is_wc_endpoint()) echo "yes";
Thank you.

The questions seemed to be answered and bit old. But i found a better solution, which may help somebody else.
you can use the following function. Documentation
is_wc_endpoint_url()
if used without a parameter, it will check current url against all endpoints. If an endpoint is specified like
is_wc_endpoint_url('edit-account');
it will check either the url is of specific endpoint or not.

Try following function:
function is_wc_endpoint() {
if ( empty( $_SERVER['REQUEST_URI'] ) ) return false;
$url = parse_url( $_SERVER['REQUEST_URI'] );
if ( empty( $url['query'] ) ) return false;
global $wpdb;
$all_woocommerce_endpoints = array();
$results = $wpdb->get_results( "SELECT option_name, option_value FROM {$wpdb->prefix}options WHERE option_name LIKE 'woocommerce_%_endpoint'", 'ARRAY_A' );
foreach ( $results as $result ) {
$all_woocommerce_endpoints[$result['option_name']] = $result['option_value'];
}
foreach ( $all_woocommerce_endpoints as $woocommerce_endpoint ) {
if ( strpos( $url['query'], $woocommerce_endpoint ) !== false ) {
return true;
}
}
return false;
}
Hope it'll give you result you are expecting.

This is a never version of the is_wc_endpoint_url function that will be included in the future woocommerce version. So just give it a different name and put into your functions.php for example.
function is_wc_endpoint_url( $endpoint = false ) {
global $wp;
$wc_endpoints = WC()->query->get_query_vars();
if ( $endpoint ) {
if ( ! isset( $wc_endpoints[ $endpoint ] ) ) {
return false;
} else {
$endpoint_var = $wc_endpoints[ $endpoint ];
}
return isset( $wp->query_vars[ $endpoint_var ] );
} else {
foreach ( $wc_endpoints as $key => $value ) {
if ( isset( $wp->query_vars[ $key ] ) ) {
return true;
}
}
return false;
}
}

I tried the default WC function:
is_wc_endpoint_url('my-custom-endpoint');
but it always returned false for me. So I created my own function:
function yourtheme_is_wc_endpoint($endpoint) {
// Use the default WC function if the $endpoint is not provided
if (empty($endpoint)) return is_wc_endpoint_url();
// Query vars check
global $wp;
if (empty($wp->query_vars)) return false;
$queryVars = $wp->query_vars;
if (
!empty($queryVars['pagename'])
// Check if we are on the Woocommerce my-account page
&& $queryVars['pagename'] == 'my-account'
) {
// Endpoint matched i.e. we are on the endpoint page
if (isset($queryVars[$endpoint])) return true;
// Dashboard my-account page special check - check whether the url ends with "my-account"
if ($endpoint == 'dashboard') {
$requestParts = explode('/', trim($wp->request, ' \/'));
if (end($requestParts) == 'my-account') return true;
}
}
return false;
}
Example:
yourtheme_is_wc_endpoint('my-custom-endpoint');
Or:
yourtheme_is_wc_endpoint('edit-account');

Related

Filter which BACS account information is sent to users via email

Implemented the following solution https://stackoverflow.com/a/55174664/1759546 with success but, how could one apply the same logic in the order confirmation emails that are sent to the users? I'm trying to send just one of many accounts available, depending on meta data from order.
Thanks in advance
Ok, so I was being dumb.
We just have to pass a second argument to woocommerce_bacs_accounts which is the order_id. And as the filter runs inside the order_email it will apply the same rules.
add_filter( 'woocommerce_bacs_accounts', 'filter_woocommerce_bacs_accounts_callback', 10, 2 );
function filter_woocommerce_bacs_accounts_callback( $bacs_accounts, $order_id ){
if ( empty($bacs_accounts) ) {
return $bacs_accounts; // Exit
}
if( is_wc_endpoint_url('order-received') ) {
$endpoint = 'order-received';
// Get the WC_Order Object
$order = wc_get_order( get_query_var($endpoint) );
} elseif( is_wc_endpoint_url('view-order') ) {
$endpoint = 'view-order';
// Get the WC_Order Object
$order = wc_get_order( get_query_var($endpoint) );
} else if ($order_id){
// Get the WC_Order Object
$order = wc_get_order($order_id );
}
$sort_codes = []; // Initializing variable array
// Loop through order items
foreach ( $order->get_items() as $item ) {
$sort_codes[] = $item->get_meta("pa_sede");
}
if ( empty($sort_codes) ) {
return $bacs_accounts; // Exit
}
// Loop through Bacs accounts
foreach ( $bacs_accounts as $key => $bacs_account ) {
$bacs_account = (object) $bacs_account;
// Remove the non matching bank accounts
if ( ! in_array($bacs_account->sort_code, $sort_codes ) ) {
unset($bacs_accounts[$key]);
}
}
return $bacs_accounts;
}

Uncaught Error: Call to a member function get_cart() on null

On Woocommerce, I have an error message on my function but i don't unserstand why it happens.
Uncaught Error: Call to a member function get_cart() on null in ...
The function checks id a category product is in the cart.
The error is displayed in the order detail in backend
It's used in functions.php , executed on checkout page,
called by these hooks:
woocommerce_before_order_notes
woocommerce_checkout_process
woocommerce_checkout_update_order_meta
woocommerce_admin_order_data_after_billing_address
woocommerce_email_order_meta_keys
https://i.stack.imgur.com/v7Atp.png
function is_in_the_cart() {
$found=false;
// Find if product is in the cart price <=40
foreach( WC()->cart->get_cart() as $cart_item_key => $values )
{
$cart_product = $values['data'];
$price = accessProtected($values['data'], 'changes')['price'];
if ($price >=40 && $cart_product->id=='969') {$found=true;}
}
if ( $found ) {
return true;
} else {
return false;
}
}
add_action('woocommerce_checkout_process', 'wps_select_checkout_field_process');
function wps_select_checkout_field_process() {
if (is_in_the_cart())
{
global $woocommerce;
// Check if set, if its not set add an error.
if ($_POST['dvd'] == "blank")
wc_add_notice( '<strong>Merci de séléctionner un DVD</strong>', 'error' );
}
}
//* Update the order meta with field value
add_action('woocommerce_checkout_update_order_meta', 'wps_select_checkout_field_update_order_meta');
function wps_select_checkout_field_update_order_meta( $order_id ) {
if (is_in_the_cart())
{
if ($_POST['dvd']) update_post_meta( $order_id, 'dvd', esc_attr($_POST['dvd']));
}
}
add_action( 'woocommerce_admin_order_data_after_billing_address', 'wps_select_checkout_field_display_admin_order_meta', 10, 1 );
function wps_select_checkout_field_display_admin_order_meta($order){
if (is_in_the_cart())
{
echo '<p><strong>DVD: </strong> ' . get_post_meta( $order->id, 'dvd', true ) . '</p>';
}
}
//* Add selection field value to emails
add_filter('woocommerce_email_order_meta_keys', 'wps_select_order_meta_keys');
function wps_select_order_meta_keys( $keys ) {
if (is_in_the_cart())
{
$keys['Dvd:'] = 'dvd';
return $keys;
}
}
I think you want to check to make sure the cart isn't empty before your function.
Also... You can access price by using get_price() from the product object which you are retrieving with $values['data']
function is_in_the_cart(){
// Make sure it's only on front end
if (is_admin()) return false;
$found = false;
// If cart is empty - bail and return false
if (empty (WC()->cart->get_cart())) {
return false;
} else {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$cart_product = $values[ 'data' ];
// Find if product is in the cart price <=40
$price = floatval($cart_product->get_price());
if ( $price >= 40 && $cart_product->id == '969' ) {
$found = true;
}
}
if ( $found ) {
return true;
} else {
return false;
}
}
}
UPDATED - added is_admin to prevent from running on backend.

Making update notice functionality for my themes

I've created one of my themes.I want to add update functionality through api
The notice should be visible when I use the theme, if required for theme update
Actually i have no idea so please give me your suggestion or give me a code,so i can add functionality for update theme.
Note : If you have a no idea for api so you can provide another code
You can use site_transient_update_themes here:
add_filter ( 'site_transient_update_themes', 'theme_check_for_update' );
function theme_check_for_update ( $transient ) {
// Check Theme is active or not.
if( empty( $transient->checked['Your-Theme-Name'] ) )
return $transient;
$request = theme_fetch_data_of_latest_version();
if ( is_wp_error( $request ) || wp_remote_retrieve_response_code( $request ) != 200 ) {
return $transient;
} else {
$response = wp_remote_retrieve_body( $request );
}
$data = json_decode( $response );
if ( version_compare( $transient->checked['Your-Theme-Name'], $data->new_version, '<' ) ) {
$transient->response['Your-Theme-Name'] = (array) $data;
add_action('admin_notices', 'theme_update_admin_notice');
}
return $transient;
}
function theme_fetch_data_of_latest_version() {
// Your API call to check for new version
$request = wp_safe_remote_get( 'https://yourdomain.com/api/upgrade-json/' );
/*
Response Shoul be in following format:
{
"new_version": "1.0.4",
"url": "https://yourdomain.com/theme/changelog/",
"package": "https://yourdomain.com/theme/theme.zip"
}
*/
return $request;
}
function theme_update_admin_notice(){
echo '<div class="notice notice-warning notice-alt is-dismissible">
<p>New Theme Update is available.</p>
</div>';
}

Pay without need to login WooCommerce

For a WooCommerce webshop we send out a lot of payment links through email. Before getting to the payment page customers are obligated to login first. We would like the customer to be able to complete payment without logging in as often they don't know their password because of different company departments.
I found this code but this only lets the administrator pay without logging in:
function your_custom_function_name($allcaps, $caps, $args)
{
if (isset($caps[0])) {
switch ($caps[0]) {
case 'pay_for_order':
$user_id = $args[1];
$order_id = isset($args[2]) ? $args[2] : null;
// When no order ID, we assume it's a new order
// and thus, customer can pay for it
if (!$order_id) {
$allcaps['pay_for_order'] = true;
break;
}
$user = get_userdata($user_id);
if (in_array('administrator', (array)$user->roles)) {
$allcaps['pay_for_order'] = true;
}
$order = wc_get_order($order_id);
if ($order && ($user_id == $order->get_user_id() || !$order - > get_user_id())) {
$allcaps['pay_for_order'] = true;
}
break;
}
}
return $allcaps;
}
add_filter('user_has_cap', 'your_custom_function_name', 10, 3);
here is working function with all users just test it :
function your_custom_function_name( $allcaps, $caps, $args ) {
if ( isset( $caps[0] ) ) {
switch ( $caps[0] ) {
case 'pay_for_order' :
$order_id = isset( $args[2] ) ? $args[2] : null;
$order = wc_get_order( $order_id );
$user = $order->get_user();
$user_id = $user->ID;
// When no order ID, we assume it's a new order
// and thus, customer can pay for it
if ( ! $order_id ) {
$allcaps['pay_for_order'] = true;
break;
}
$order = wc_get_order( $order_id );
if ( $order && ( $user_id == $order->get_user_id() || ! $order->get_user_id() ) ) {
$allcaps['pay_for_order'] = true;
}
break;
}
}
return $allcaps;
}
add_filter( 'user_has_cap', 'your_custom_function_name', 10, 3 );
I have created a different solution for this problem, allowing anyone who has the WooCommerce-generated Payment URL (which includes the Order Key) to complete the payment for that order. (So we retain some of the security/protection, rather than just allowing anyone to pay for anything and see any order.)
function allow_payment_without_login( $allcaps, $caps, $args ) {
// Check we are looking at the WooCommerce Pay For Order Page
if ( !isset( $caps[0] ) || $caps[0] != 'pay_for_order' )
return $allcaps;
// Check that a Key is provided
if ( !isset( $_GET['key'] ) )
return $allcaps;
// Find the Related Order
$order = wc_get_order( $args[2] );
if( !$order )
return $allcaps; # Invalid Order
// Get the Order Key from the WooCommerce Order
$order_key = $order->get_order_key();
// Get the Order Key from the URL Query String
$order_key_check = $_GET['key'];
// Set the Permission to TRUE if the Order Keys Match
$allcaps['pay_for_order'] = ( $order_key == $order_key_check );
return $allcaps;
}
add_filter( 'user_has_cap', 'allow_payment_without_login', 10, 3 );
Using this function, a user visiting a URL which has an Order Number, and the associated Order Key, will be able to complete the payment, but if the Order Key is not valid, or not present, then it will fail.
Examples:
your.domain/checkout/order-pay/987/?pay_for_order=true&key=wc_order_5c4155dd4462cPASS if "wc_order_5c4155dd4462c" is Order Key for Order #987
your.domain/checkout/order-pay/987/?pay_for_order=trueFAIL as No Key Parameter Present
your.domain/checkout/order-pay/987/FAIL as No Key Parameter Present

login_redirect hook redirect not working

I used login_redirect hook for redirect to custom url. while i use $redirect_to. It is now working. But while i echo $redirect_to it shows correct url.
I have set the redirect_to parameter in login form also.
function my_login_redirect( $redirect_to, $request, $user ) {
echo $redirect_to;
//is there a user to check?
if ( isset( $user->roles ) && is_array( $user->roles ) ) {
//check for admins
if ( in_array( 'administrator', $user->roles ) ) {
// redirect them to the default place
return $redirect_to;
} else {
// return home_url();
return $redirect_to;
die();
}
} else {
return $redirect_to;
}
}
add_filter( 'login_redirect', 'my_login_redirect', 10, 3 );
well i found the solution. i used wp_redirect() inside my_login_redirect() i when the user is not administrator.

Resources