Detecting if the current user has an active subscription - php

I'm developing a website in WordPress with WooCommerce. I'm using additionally WC Paid Listings and WooCommerce Subscriptions plugins to handle my work.
The problem is when a user with "subscriber" role with an active subscription login tries to post content every time he/she has to choose a package even if he has an active subscription.
Is there anyone with an idea of how to detect if the user has an active subscription, if it returns true then the step choosing package is skipped?

Updated (2019)
New conditional function using WooCommerce Subscriptions wcs_user_has_subscription().
New conditional function using a much lighter code version (SQL query).
Original enhanced conditional function based on an improved WP_Query.
The following custom conditional functions have an optional argument $user_id (a defined user_id) and will return true when the current user (or a defined user) has active subscriptions.
So this can be done now using 3 different ways (that do the same thing):
1) Using WooCommerce Subscriptions dedicated conditional function wcs_user_has_subscription():
function has_active_subscription( $user_id='' ) {
// When a $user_id is not specified, get the current user Id
if( '' == $user_id && is_user_logged_in() )
$user_id = get_current_user_id();
// User not logged in we return false
if( $user_id == 0 )
return false;
return wcs_user_has_subscription( $user_id, '', 'active' );
}
2) The same thing with a much lighter SQL query (added on March 2019):
function has_active_subscription( $user_id=null ) {
// When a $user_id is not specified, get the current user Id
if( null == $user_id && is_user_logged_in() )
$user_id = get_current_user_id();
// User not logged in we return false
if( $user_id == 0 )
return false;
global $wpdb;
// Get all active subscriptions count for a user ID
$count_subscriptions = $wpdb->get_var( "
SELECT count(p.ID)
FROM {$wpdb->prefix}posts as p
JOIN {$wpdb->prefix}postmeta as pm
ON p.ID = pm.post_id
WHERE p.post_type = 'shop_subscription'
AND p.post_status = 'wc-active'
AND pm.meta_key = '_customer_user'
AND pm.meta_value > 0
AND pm.meta_value = '$user_id'
" );
return $count_subscriptions == 0 ? false : true;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
3) The original enhanced code, that will also do the same:
function has_active_subscription( $user_id=null ) {
// When a $user_id is not specified, get the current user Id
if( null == $user_id && is_user_logged_in() )
$user_id = get_current_user_id();
// User not logged in we return false
if( $user_id == 0 )
return false;
// Get all active subscriptions for a user ID
$active_subscriptions = get_posts( array(
'numberposts' => 1, // Only one is enough
'meta_key' => '_customer_user',
'meta_value' => $user_id,
'post_type' => 'shop_subscription', // Subscription post type
'post_status' => 'wc-active', // Active subscription
'fields' => 'ids', // return only IDs (instead of complete post objects)
) );
return sizeof($active_subscriptions) == 0 ? false : true;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Update of usage:
1) USAGE for the current user:
if( has_active_subscription() ){ // Current user has an active subscription
// do something … here goes your code
// Example of displaying something
echo '<p>I have active subscription</p>';
}
2) USAGE for a defined user ID:
if( has_active_subscription(26) ){ // Defined User ID has an active subscription
// do something … here goes your code
// Example of displaying something
echo '<p>User ID "26" have an active subscription</p>';
}
This code is tested and it works
Related answers:
WooCommerce Subscriptions - Check if product already has an active subscriber
WooCommerce - Get active subscriptions in a list between start / end date

Use wcs_user_has_subscription()
$has_sub = wcs_user_has_subscription( '', '', 'active' );
if ( $has_sub) {
// User have active subscription
}

Related

Woocommerce Subscription access from external php

I have a Wordpress website with Woocommerce and Woocommerce Subscription plugins.
I need to write some PHP script that will check if a user has active subscription status.
From the database, I would like to get information: user id, status (if it's active - if payment was made and the subscription was renewed), end date of subscription...
The problem is that I don't even know where subscription info is saved?
Can somebody write me a snippet of code, that includes a query that will give me a list of users that subscribed, with the necessary information mentioned earlier?
I will post an update with code later, for now, I just need help with query and guidance where to look in the database tables.
I think what you meant is you want to access the Wordpress/Woocommerce Subscriptions API from a PHP file within your Wordpress installation. To do this I think the following will help:
Create a folder in wp-content/plugins called woocommerce-subscriptions-status-checker
Create a file called woocommerce-subscriptions-status-checker.php inside the above new folder.
Add this code in the file:
/*
Plugin Name: Woocommerce Subscriptions Status Checker
Plugin URI: http://www.XXXXXX.com
Description: XXXXXXXXX
Author: XXXXXX
Version: 2.0
Author URI: http://www.XXXXX.com
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class WC_Subscriptions_Status_Checker {
function __construct() {
// Avoids the function firing if we are in wp-admin backend
if ( !is_admin() ) {
// Fires on every page load after WordPress, all plugins, and the theme are fully loaded and instantiated
add_action( 'wp-loaded', array( $this, 'check_current_user' ) );
}
}
function check_current_user() {
// Check if user is even logged in, if not exit
if ( !is_user_logged_in() ) return;
$current_user = wp_get_current_user(); // get current WP_User
$user_id = $current_user->ID; // get user id
$is_subscription = wcs_user_has_subscription( $user_id ); // check if user has subscription
if ( $is_subscription )
{
$subscriptions = wcs_get_users_subscriptions( $user_id ); // get array of all subscriptions
// Check if there is one subscription or multiple subscriptions per user
if ( count( $subscriptions ) > 1 ) {
// Example if you wanted to loop through all subscriptions, in the case of the user having multiple subscriptions
foreach ( $subscriptions as $sub_id => $subscription ) {
if ( $subscription->get_status() == 'active' ) {
// Do something
}
}
} else { // Only 1 subscription
$subscription = reset( $subscriptions ); // gets first and only value
if ( $subscription->get_status() == 'active' ) {
// Do something
}
}
}
}
}
new WC_Subscriptions_Status_Checker();
Visit the plugins section of wp-admin and Activate your new plugin.
Here is my solution (not saying that it's the best, but for me, it solved the problem that I had).
Code in function.php (WP child theme)
add_action('init','getWPuser');
function getWPuser(){
$current_user = wp_get_current_user();
return $current_user;
}
Custom website
Code in my custom site that needs information about the user.
require_once '../wp-load.php';
require_once '../wp-content/themes/h-code-child/functions.php';
require_once '../wp-includes/pluggable.php';
require_once '../wp-blog-header.php';
$current_user = getWPuser();
Saving user ID information.
$logged_user_id = $current_user->ID;
Checking on specific subscription if it's active.
$has_free = wcs_user_has_subscription( $logged_user_id, $product_id, 'active' );
You can try Woocommerce REST API.
https://docs.woocommerce.com/document/woocommerce-rest-api/
Basically, Woocommerce provide a restful API to access the data and interact with the ecommerce system outside of the traditional woocommerce workflow.

Change woocommerce subscription "shop" link inside my account page

I'm a newbie in coding and currently using woocommerce subscription plugin and wanted to change the default "shop" if I don't have any subscription. I want it to link to a specific product instead of the shop.
I want to change the red part:
Below are the current code for this section:
<?php
// translators: placeholders are opening and closing link tags to take to the shop page
printf( esc_html__( 'Anda masih belum melanggan. Mula melanggan %sdi sini%s.', 'woocommerce-subscriptions' ), '', '' );
?>
</p>
<?php endif; ?>
I want to change the example.com/shop into something like example.com/product-category/myproduct
Any help will be appreciated.
To achieve that, you will need:
A conditional function that detect if the current user has an active subscription
A custom function hooked in woocommerce_subscriptions_message_store_url filter hook, where you will define your new URL linked to your product.
Here is the code:
// Conditional function detecting if the current user has an active subscription
function has_active_subscription( $user_id=null ) {
// if the user_id is not set in function argument we get the current user ID
if( null == $user_id )
$user_id = get_current_user_id();
// Get all active subscrptions for a user ID
$active_subscriptions = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => $user_id,
'post_type' => 'shop_subscription', // Subscription post type
'post_status' => 'wc-active', // Active subscription
) );
// if user has an active subscription
if( ! empty( $active_subscriptions ) ) return true;
else return false;
}
// Change woocommerce subscription “shop” link inside my account page
add_filter( 'woocommerce_subscriptions_message_store_url', 'custom_subscriptions_message_store_url', 10, 1 );
function custom_subscriptions_message_store_url( $url ){
// If current user has NO active subscriptions
if( ! has_active_subscription() ){
// HERE Define below the new URL linked to your product.
$url = home_url( "/product-category/myproduct/" );
}
return $url;
}
This code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works

WooCommerce Memberships: Conditional to check a page access

I have a Wordpress Memberships website that is built on WooCommerce with WooCommerce Memberships plugin to restrict certain pages to members only.
Some of those pages are "drip-fed"... ie. Access to those pages opens 3 days after purchase, etc. I have set this up in WooMemberships.
I am trying to simply do a PHP conditional check to see if the current user has access to a certain page.
I have found this code piece in the docs: wc_memberships_is_post_content_restricted()
However, I have been unable to make it work.
Is there a code snippet which will basically do a PHP IF statement on whether the current user has access to a certain page (using page ID)?
eg:
if ( current_user_has_access(page_ID) ) { DO SOMETHING } else { DON'T }
Thanks.
I'm not sure if this helps but here is my take on it. I first go through all of the users active membership and then I check the content $rules to see if the restricted plans are a part of the users membership plans (in_array)
function can_user_access_content($user_id,$post_id){
//check if there's a force public on this content
if(get_post_meta($post_id,'_wc_memberships_force_public',true)=='yes') return true;
$args = array( 'status' => array( 'active' ));
$plans = wc_memberships_get_user_memberships( $user_id, $args );
$user_plans = array();
foreach($plans as $plan){
array_push($user_plans,$plan->plan_id);
}
$rules = wc_memberships()->get_rules_instance()->get_post_content_restriction_rules( $post_id );
foreach($rules as $rule){
if(in_array($rule->get_membership_plan_id(), $user_plans)){
return true;
}
}
return false;
}
Usage would be something like:
if(can_user_access_content(get_current_user_id(),$post->ID)){
//do whatever here
}
I'm dealing with the same issue at StoryMoment.com (we produce audio + eBook story series for kids).
This is how I've dealt with it. I use the following in a page template to show or hide page elements based on access. The wc_memberships_view_delayed_post_content would change based on the type of content.
You can see the other options in the file:
class-wc-memberships-capabilities.php
<?php
$has_access = current_user_can( 'wc_memberships_view_delayed_post_content', $post->ID );
if ($has_access) {
//do something
} else {
//do something else
}
?>
You will have to Replace (in the conditions):
$page_id by your page ID number (for example: is_page(42))
$membership_plan by the slug of the plan ('plan_slug') or related post ID.
The conditions:
wc_memberships_is_post_content_restricted($page_id) => true if $page_id is retracted.
is_page($page_id) => true if is actual $page_id.
wc_memberships_is_user_active_member( $membership_plan ) => true actual user is an active member for this $membership_plan plan. In that case the access to the page is granted by the suscription plan of the user.
You can remove some of the conditions, if not needed, and fine tune for your needs.
if( wc_memberships_is_post_content_restricted() && is_page($page_id) && wc_memberships_is_user_active_member( $membership_plan ) ) {
// do something
} else {
// don't
}
--- Update ---
The only function related to restriction and (or) time access are:
1) wc_memberships_restrict( $content, $membership_plans, $delay, $exclude_trial ) just like shortcode [wcm_restrict] (so not useful)…
2) wc_memberships_get_user_access_time( $user_id, $target, $action, $gmt ): Parameters
$user_id // for a logged 'user ID'
$target : array('post' => id, 'product' => id) // content_type and content_id
$action : 'view' or 'purchase' // Type of access (products only)<br>
$gmt => : true or false // (selection of the time zone)
// Returns user access start timestamp (in site timezone) for content or a product
Reference: WooCommerce Memberships Function Reference

Check if user is in a group on the main site FROM a subsite of a network (WP Multisite)

I'm using Woocommerce + the groups plugin on my main site to promote users to a 'Premium' group upon purchasing items which works great.
If a user on the main site then browses to the second site within my network, I can no longer check to see if they're within the 'Premium' group.
On my main site, I can use this code:
<?php
$user_id = get_current_user_id();
$group = Groups_Group::read_by_name( 'Premium' );
if ( Groups_User_Group::read( $user_id, $group->group_id ) ) {
?>
Premium content here!
<?php } ?>
But this does not work on the subsite. Is there anyway I can check to see if the user is in a group on my main site FROM a subsite?
I managed to achieve this using the following code:
<?php
$blog_id = 1; //set the blog id to the main site id
switch_to_blog( $blog_id );
$user_id = get_current_user_id();
$group = Groups_Group::read_by_name( 'Premium' );
if ( Groups_User_Group::read( $user_id, $group->group_id ) ) {
echo 'PREMIUM!!';
} else {
echo 'Not premium';
}
restore_current_blog();
?>
Probably not a definitive answer but this should lead to it at least.
Your current code is using a wordpress function to get the users id. This should work across the board and is therefore fine. The next variabe/method uses the class from the groups plugin which I presume is just not being pulled on the subsite.
$user_id = get_current_user_id();
$group = Groups_Group::read_by_name( 'Premium' );
Groups_User_Group::read( $user_id, $group->group_id )
From the look of the class files
$group = Groups_Group::read_by_name( 'Premium' );
This line simply does the method below
public static function read_by_name( $name ) {
global $wpdb;
$result = false;
$group_table = _groups_get_tablename( 'group' );
$group = $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM $group_table WHERE name = %s",
$name
) );
if ( isset( $group->group_id ) ) {
$result = $group;
}
return $result;
}
The next line
Groups_User_Group::read( $user_id, $group->group_id )
Does this method
public static function read( $user_id, $group_id ) {
global $wpdb;
$result = false;
$user_group_table = _groups_get_tablename( 'user_group' );
$user_group = $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM $user_group_table WHERE user_id = %d AND group_id = %d",
Groups_Utility::id( $user_id ),
Groups_Utility::id( $group_id )
) );
if ( $user_group !== null ) {
$result = $user_group;
}
return $result;
}
So all you are doing is pretty simple calls to the database. The issue being that due to the use of multisite there will be discrepancies with the table prefixes etc.
According to this part of the codex
http://codex.wordpress.org/Class_Reference/wpdb#Multi-Site_Variables
You can access other sites on the network much in the same way you can access the current site using $wpdb as a global variable. Therefore once you have ascertained the correct names of your tables, you should be able to modify these methods into simple functions that do the necessary work.
The first method doesn't even need to be used
$group = Groups_Group::read_by_name( 'Premium' );
As $group simply equals the id shown in the dashboard
Therefore the line can be coded statically ie
$group = 2;
The second method is purely checking if there is an entry of user_id 2 for example and group_id 2 say, in the group_users_group table. Here we have user 2 with both registered and premium group privileges. Shown here.
Therefore user 2 (again id can be seen in the dashboard in the users section) will qualify.
I hope this helps.

Allow users to manage only comments on their own posts

I want to restrict contributer and author users to seeing and manageing comments only on their own posts.
I have tried the following filter with no success.
//Manage Your Own Comments Only
function myplugin_comments_thisuseronly( $wp_query ) {
if ( strpos( $_SERVER[ 'REQUEST_URI' ], '/wp-admin/edit-comments.php' ) !== false ) {
if ( !current_user_can( 'edit_others_posts' ) ) {
global $current_user;global $wpdb;
$usersposts = $wpdb->get_results( $wpdb->prepare("SELECT ID FROM wp_posts WHERE post_author = %s", $current_user->id) );
$wp_query->set('comment_post_ID', array($usersposts));
}
}
}
add_filter('parse_query', 'myplugin_comments_thisuseronly' );
I also tried
$wp_query->set('comment_post_ID__in', array($usersposts));
Ok, I figured this out.
First, the user needs to have a role with permission to edit published posts AND to moderate comments. The latter is not standard for authors/contributors.
Then, by filtering the query which gets the comments (using comments_clauses) and adding a join you can show only comments for posts by the currently logged in user.
function my_plugin_get_comment_list_by_user($clauses) {
if (is_admin()) {
global $user_ID, $wpdb;
$clauses['join'] = ", wp_posts";
$clauses['where'] .= " AND wp_posts.post_author = ".$user_ID." AND wp_comments.comment_post_ID = wp_posts.ID";
};
return $clauses;
};
// Ensure that editors and admins can moderate all comments
if(!current_user_can('edit_others_posts')) {
add_filter('comments_clauses', 'my_plugin_get_comment_list_by_user');
}
Works perfectly. The changes to roles may not suit every setup, but as it happens it does work for me on this site.

Categories