/** * Programmatically create a user membership * Example: automatically grant membership access to a plan at WP user registration * Requires Memberships 1.3+ * * @param int $user_id the ID of the newly created user */ function sv_wc_memberships_user_membership_at_registration($user_id) { // bail if Memberships isn't active if (!function_exists('wc_memberships')) { return; } $args = array('plan_id' => 253, 'user_id' => $user_id); // magic! wc_memberships_create_user_membership($args); // Optional: get the new membership and add a note so we know how this was registered. $user_membership = wc_memberships_get_user_membership($user_id, $args['plan_id']); $user_membership->add_note('Membership access granted automatically from registration.'); }
/** * Import user membership from group membership * * @since 1.0.0 * @param int $user_id * @param int $group_id * @param int $plan_id * @return int|bool Imported membership ID or false on skip/failure */ private function import_user_membership($user_id, $group_id, $plan_id) { // User is already a member, skip if (wc_memberships_is_user_member($user_id, $plan_id)) { return false; } /** * Filter new membership data, used when importing membership from Groups * * @param array $data * @param array $args */ $data = apply_filters('wc_memberships_groups_import_membership_data', array('post_parent' => $plan_id, 'post_author' => $user_id, 'post_type' => 'wc_user_membership', 'post_status' => 'wcm-active', 'comment_status' => 'open'), array('user_id' => $user_id, 'group_id' => $group_id)); // Create a new membership $user_membership_id = wp_insert_post($data); // Bail out on failure if (is_wp_error($user_membership_id)) { return false; } // Save group ID that granted access update_post_meta($user_membership_id, '_group_id', $group_id); // Save the membership start date update_post_meta($user_membership_id, '_start_date', current_time('mysql', true)); // Calculate membership end date based on membership length $plan = wc_memberships_get_membership_plan($plan_id); $end_date = ''; if ($plan->get_access_length_amount()) { $now = current_time('timestamp'); if (strpos($plan->get_access_length_period(), 'month') !== false) { $end = wc_memberships()->add_months($now, $plan->get_access_length_amount()); } else { $end = strtotime('+ ' . $plan->get_access_length(), $now); } $end_date = date('Y-m-d H:i:s', $end); } // Save/update end date $user_membership = wc_memberships_get_user_membership($user_membership_id); $user_membership->set_end_date($end_date); // Add membership note $group = Groups_Group::read($group_id); $user_membership->add_note(sprintf(__('Membership imported from Group "%s" (ID #%d)'), $group->name, $group_id)); return $user_membership_id; }
/** * Trigger the membership note email * * @param array $args Optional */ function trigger($args) { if ($args && isset($args['notify']) && $args['notify']) { $defaults = array('user_membership_id' => '', 'membership_note' => ''); $args = wp_parse_args($args, $defaults); extract($args); if ($user_membership_id && ($this->object = wc_memberships_get_user_membership($user_membership_id))) { $user = get_userdata($this->object->get_user_id()); $this->recipient = $user->user_email; $this->membership_note = $membership_note; } else { return; } } if (!$this->is_enabled() || !$this->get_recipient()) { return; } $this->send($this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments()); }
/** * Add user membership note * * @since 1.0.0 */ public function add_user_membership_note() { check_ajax_referer('add-user-membership-note', 'security'); $post_id = (int) $_POST['post_id']; $note_text = wp_kses_post(trim(stripslashes($_POST['note']))); $notify = isset($_POST['notify']) && $_POST['notify'] == 'true'; if ($post_id > 0) { $user_membership = wc_memberships_get_user_membership($post_id); $comment_id = $user_membership->add_note($note_text, $notify); $note = get_comment($comment_id); $plan = $user_membership->get_plan(); /* translators: Placeholder for plan name if a plan has been removed */ $plan_name = $plan ? $plan->get_name() : __('[Plan removed]', WC_Memberships::TEXT_DOMAIN); $note_classes = get_comment_meta($note->comment_ID, 'notified', true) ? array('notified', 'note') : array('note'); echo '<div>'; echo '<ul id="notes">'; include 'admin/meta-boxes/views/html-membership-note.php'; echo '</ul>'; echo '<ul id="recent-activity">'; include 'admin/meta-boxes/views/html-membership-recent-activity-note.php'; echo '</ul>'; echo '</div>'; } exit; }
/** * Pause subscription-based memberships * * Find any memberships that are on free trial and pause them * * @since 1.0.0 */ public function pause_free_trial_subscription_memberships() { $args = array('post_type' => 'wc_user_membership', 'post_status' => 'wcm-free_trial', 'nopaging' => true); $posts = get_posts($args); // Bail out if there are no memberships on free trial if (empty($posts)) { return; } foreach ($posts as $post) { $user_membership = wc_memberships_get_user_membership($post); $user_membership->pause_membership(__('Membership paused because WooCommerce Subscriptions was deactivated.', WC_Memberships::TEXT_DOMAIN)); } }
/** * Checks if a user has a certain capability * * @since 1.0.0 * @param array $allcaps * @param array $caps * @param array $args * @return array */ public function user_has_cap($allcaps, $caps, $args) { global $pagenow, $typenow; if (isset($caps[0])) { switch ($caps[0]) { case 'wc_memberships_access_all_restricted_content': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } break; case 'wc_memberships_view_restricted_post_content': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } $user_id = $args[1]; $post_id = $args[2]; if ($this->post_is_public($post_id)) { $allcaps[$caps[0]] = true; break; } $rules = wc_memberships()->rules->get_post_content_restriction_rules($post_id); $allcaps[$caps[0]] = wc_memberships()->rules->user_has_content_access_from_rules($user_id, $rules, $post_id); break; case 'wc_memberships_view_restricted_product': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } $user_id = $args[1]; $post_id = $args[2]; if ($this->post_is_public($post_id)) { $allcaps[$caps[0]] = true; break; } $rules = wc_memberships()->rules->get_the_product_restriction_rules($post_id); $allcaps[$caps[0]] = wc_memberships()->rules->user_has_product_view_access_from_rules($user_id, $rules, $post_id); break; case 'wc_memberships_purchase_restricted_product': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } $user_id = $args[1]; $post_id = $args[2]; if ($this->post_is_public($post_id)) { $allcaps[$caps[0]] = true; break; } $rules = wc_memberships()->rules->get_the_product_restriction_rules($post_id); $allcaps[$caps[0]] = wc_memberships()->rules->user_has_product_purchase_access_from_rules($user_id, $rules, $post_id); break; case 'wc_memberships_view_restricted_taxonomy_term': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } $user_id = $args[1]; $taxonomy = $args[2]; $term_id = $args[3]; $rules = wc_memberships()->rules->get_taxonomy_term_content_restriction_rules($taxonomy, $term_id); $allcaps[$caps[0]] = wc_memberships()->rules->user_has_content_access_from_rules($user_id, $rules, $term_id); break; case 'wc_memberships_view_restricted_taxonomy': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } $user_id = $args[1]; $taxonomy = $args[2]; $rules = wc_memberships()->rules->get_taxonomy_content_restriction_rules($taxonomy); $allcaps[$caps[0]] = wc_memberships()->rules->user_has_content_access_from_rules($user_id, $rules); break; case 'wc_memberships_view_restricted_post_type': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } $user_id = $args[1]; $post_type = $args[2]; if (in_array($post_type, array('product', 'product_variation'))) { $rules = wc_memberships()->rules->get_product_restriction_rules(array('content_type' => 'post_type', 'content_type_name' => 'product')); $allcaps[$caps[0]] = wc_memberships()->rules->user_has_product_view_access_from_rules($user_id, $rules); } else { $rules = wc_memberships()->rules->get_post_type_content_restriction_rules($post_type); $allcaps[$caps[0]] = wc_memberships()->rules->user_has_content_access_from_rules($user_id, $rules); } break; case 'wc_memberships_view_delayed_post_type': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } $user_id = $args[1]; $post_type = $args[2]; $has_access = false; $access_time = $this->get_user_access_start_time_for_post_type($user_id, $post_type); if ($access_time && current_time('timestamp', true) >= $access_time) { $has_access = true; } $allcaps[$caps[0]] = $has_access; break; case 'wc_memberships_view_delayed_taxonomy': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } $user_id = $args[1]; $taxonomy = $args[2]; $has_access = false; $access_time = $this->get_user_access_start_time_for_taxonomy($user_id, $taxonomy); if ($access_time && current_time('timestamp', true) >= $access_time) { $has_access = true; } $allcaps[$caps[0]] = $has_access; break; case 'wc_memberships_view_delayed_taxonomy_term': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } $user_id = $args[1]; $taxonomy = $args[2]; $term = $args[3]; $has_access = false; $access_time = $this->get_user_access_start_time_for_taxonomy_term($user_id, $taxonomy, $term); if ($access_time && current_time('timestamp', true) >= $access_time) { $has_access = true; } $allcaps[$caps[0]] = $has_access; break; case 'wc_memberships_view_delayed_post_content': case 'wc_memberships_view_delayed_product': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } $user_id = $args[1]; $post_id = $args[2]; $has_access = false; if ($this->post_is_public($post_id)) { $allcaps[$caps[0]] = true; break; } $access_time = $this->get_user_access_start_time_for_post($user_id, $post_id, 'view'); if ($access_time && current_time('timestamp', true) >= $access_time) { $has_access = true; } $allcaps[$caps[0]] = $has_access; break; case 'wc_memberships_purchase_delayed_product': if ($this->can_manage_woocommerce($allcaps)) { $allcaps[$caps[0]] = true; break; } $user_id = $args[1]; $post_id = $args[2]; $has_access = false; if ($this->post_is_public($post_id)) { $allcaps[$caps[0]] = true; break; } $access_time = $this->get_user_access_start_time_for_post($user_id, $post_id, 'purchase'); if ($access_time && current_time('timestamp', true) >= $access_time) { $has_access = true; } $allcaps[$caps[0]] = $has_access; break; // Editing a rule depends on the rule's content type and related capabilities // Editing a rule depends on the rule's content type and related capabilities case 'wc_memberships_edit_rule': $user_id = $args[1]; $rule_id = $args[2]; $can_edit = false; $rule = wc_memberships()->rules->get_rule($rule_id); if ($rule) { switch ($rule->get_content_type()) { case 'post_type': $post_type = get_post_type_object($rule->get_content_type_name()); if (!$post_type) { return false; } $can_edit = current_user_can($post_type->cap->edit_posts) && current_user_can($post_type->cap->edit_others_posts); break; case 'taxonomy': $taxonomy = get_taxonomy($rule->get_content_type_name()); if (!$taxonomy) { return false; } $can_edit = current_user_can($taxonomy->cap->manage_terms) && current_user_can($taxonomy->cap->edit_terms); break; } } $allcaps[$caps[0]] = $can_edit; break; case 'wc_memberships_cancel_membership': case 'wc_memberships_renew_membership': $user_id = $args[1]; $user_membership_id = $args[2]; $user_membership = wc_memberships_get_user_membership($user_membership_id); // complimentary memberships cannot be cancelled or renewed by the user $allcaps[$caps[0]] = $user_membership && $user_membership->get_user_id() == $user_id && !$user_membership->has_status('complimentary'); break; // Prevent deleting membership plans with active memberships // Prevent deleting membership plans with active memberships case 'delete_published_membership_plan': case 'delete_published_membership_plans': // This workaround (*hack*, *cough*) allows displaying the trash/delete // link on membership plans list table even if the plan has active members if (is_admin() && 'edit.php' == $pagenow && 'wc_membership_plan' == $typenow && empty($_POST)) { break; } $post_id = $args[2]; $plan = wc_memberships_get_membership_plan($post_id); if ($plan->has_active_memberships()) { $allcaps[$caps[0]] = false; } break; } } return $allcaps; }
/** * Renew a membership * * @since 1.0.0 */ public function renew_membership() { if (!isset($_GET['renew_membership']) || !isset($_GET['user_membership_id'])) { return; } $user_membership_id = absint($_GET['user_membership_id']); $user_membership = wc_memberships_get_user_membership($user_membership_id); $membership_plan = $user_membership->get_plan(); $user_can_renew = current_user_can('wc_memberships_renew_membership', $user_membership_id); if (!$user_membership) { wc_add_notice(__('Invalid membership.', WC_Memberships::TEXT_DOMAIN), 'error'); } else { /** * Filter the valid statuses for renewing a user membership on frontend * * @since 1.0.0 * @param array $statuses Array of statuses valid for renewal */ $user_membership_can_renew = in_array($user_membership->get_status(), apply_filters('wc_memberships_valid_membership_statuses_for_renewal', array('expired', 'cancelled'))); // Try to purchase the same product as before $original_product = $user_membership->get_product(); if ($original_product && $original_product->is_purchasable()) { $product = $original_product; } else { foreach ($membership_plan->get_product_ids() as $product_id) { $another_product = wc_get_product($product_id); // We've found a product that can be purchased to renew access! if ($another_product && $another_product->is_purchasable()) { $product = $another_product; break; } } } // We can renew! Let's do it! if ($product && $user_can_renew && $user_membership_can_renew && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'wc_memberships-renew_membership')) { woocommerce_empty_cart(); WC()->cart->add_to_cart($product->id, 1); wc_add_notice(sprintf(__('Renew your membership by purchasing %s.', WC_Memberships::TEXT_DOMAIN), $product->get_title()), 'success'); wp_safe_redirect(WC()->cart->get_checkout_url()); exit; } } wc_add_notice(__('Cannot renew this membership. Please contact us if you need assistance.', WC_Memberships::TEXT_DOMAIN), 'error'); wp_safe_redirect(SV_WC_Plugin_Compatibility::wc_get_page_permalink('myaccount')); exit; }
/** * Display the membership notes meta box * * @param WP_Post $post * @since 1.0.0 */ public function output(WP_Post $post) { global $pagenow; // Prepare variables $user_membership = wc_memberships_get_user_membership($post->ID); $user_id = 'post.php' == $pagenow ? $user_membership->get_user_id() : (isset($_GET['user']) ? $_GET['user'] : null); // Bail out if no user ID if (!$user_id) { return; } $notes = $user_membership->get_notes(); /** * Fires at the beginning of the user membership notes meta box * * @since 1.0.0 * @param WC_Memberships_User_Membership $user_membership The user membership */ do_action('wc_memberships_before_user_membership_notes', $user_membership); ?> <div class="wc-user-membership-add-note"> <h4><?php esc_html_e('Add note', 'woocommerce'); ?> <img class="help_tip" data-tip="<?php esc_attr_e('Add a note for your reference, or add a customer note (the user will be notified).', WC_Memberships::TEXT_DOMAIN); ?> " src="<?php echo esc_url(WC()->plugin_url()); ?> /assets/images/help.png" height="16" width="16" /></h4> <p> <textarea name="user_membership_note" id="user-membership-note" class="input-text" cols="100" rows="5"></textarea> </p> <p class="note-controls"> <label> <input type="checkbox" name="notify_member" id="note-notify" class="notify-member" value="1" /> <?php esc_html_e('Notify Member', WC_Memberships::TEXT_DOMAIN); ?> </label> <a href="#" class="add-note js-add-note button"><?php esc_html_e('Add Note', WC_Memberships::TEXT_DOMAIN); ?> </a> </p> </div> <?php echo '<ul class="wc-user-membership-notes">'; if ($notes) { foreach ($notes as $note) { $note_classes = get_comment_meta($note->comment_ID, 'notified', true) ? array('notified', 'note') : array('note'); include 'views/html-membership-note.php'; } } else { echo '<li>' . esc_html__('There are no notes yet.', WC_Memberships::TEXT_DOMAIN) . '</li>'; } echo '</ul>'; /** * Fires at the end of the user membership notes meta box * * @since 1.0.0 * @param WC_Memberships_User_Membership $user_membership The user membership */ do_action('wc_memberships_after_user_membership_notes', $user_membership); }
/** * Create a new user membership programmatically * * Returns a new user membership object on success which can then be used to add additional data. * * @since 1.3.0 * @param array $args Array of arguments * @param string $action Action - either 'create' or 'renew'. When in doubt, use 'create' * @return WC_Memberships_User_Membership on success, WP_Error on failure */ function wc_memberships_create_user_membership($args = array(), $action = 'create') { $defaults = array('user_membership_id' => 0, 'plan_id' => 0, 'user_id' => 0, 'product_id' => 0, 'order_id' => 0); $args = wp_parse_args($args, $defaults); $data = array('post_parent' => $args['plan_id'], 'post_author' => $args['user_id'], 'post_type' => 'wc_user_membership', 'post_status' => 'wcm-active', 'comment_status' => 'open'); if ($args['user_membership_id'] > 0) { $updating = true; $data['ID'] = $args['user_membership_id']; } else { $updating = false; } /** * Filter new membership data, used when a product purchase grants access * * @param array $data * @param array $args */ $data = apply_filters('wc_memberships_new_membership_data', $data, array('user_id' => $args['user_id'], 'product_id' => $args['product_id'], 'order_id' => $args['order_id'])); if ($updating) { $user_membership_id = wp_update_post($data); } else { $user_membership_id = wp_insert_post($data); } // Bail out on error if (is_wp_error($user_membership_id)) { return $user_membership_id; } // Save/update product and order id that granted access if ($args['product_id'] > 0) { update_post_meta($user_membership_id, '_product_id', $args['product_id']); } if ($args['order_id'] > 0) { update_post_meta($user_membership_id, '_order_id', $args['order_id']); } // Save/update the membership start date, but only if the membership // is not active, ie is not being renewed early. if ('renew' != $action) { update_post_meta($user_membership_id, '_start_date', current_time('mysql', true)); } // Get the membership plan object so we can calculate end time $plan = wc_memberships_get_membership_plan($args['plan_id']); // Calculate membership end date based on membership length, optionally // from the existing end date, if renewing early $end_date = ''; if ($plan->get_access_length_amount()) { // Early renewals add to the existing membership length, normal // cases calculate membership length from now $now = 'renew' == $action ? strtotime(get_post_meta($user_membership_id, '_end_date', true)) : current_time('timestamp'); if (strpos($plan->get_access_length_period(), 'month') !== false) { $end = wc_memberships()->add_months($now, $plan->get_access_length_amount()); } else { $end = strtotime('+ ' . $plan->get_access_length(), $now); } $end_date = date('Y-m-d H:i:s', $end); } // Save/update end date $user_membership = wc_memberships_get_user_membership($user_membership_id); $user_membership->set_end_date($end_date); /** * Fires after a user has been granted membership access * * @since 1.3.0 * @param WC_Memberships_Membership_Plan $membership_plan The plan that user was granted access to * @param array $args */ do_action('wc_memberships_user_membership_created', $plan, array('user_id' => $args['user_id'], 'user_membership_id' => $user_membership->get_id())); return $user_membership; }
/** * Cancel a membership * * @since 1.0.0 */ public function cancel_membership() { if (empty($_REQUEST['post'])) { return; } // Get the post $id = isset($_REQUEST['post']) ? absint($_REQUEST['post']) : ''; check_admin_referer('wc-memberships-cancel-membership-' . $id); $user_membership = wc_memberships_get_user_membership($id); $user_membership->cancel_membership(); wp_redirect(add_query_arg(array('cancelled' => 1, 'ids' => $_REQUEST['post']), $this->get_sendback_url())); exit; }
/** * Save user membership data * * @since 1.0.0 * @param int $post_id * @param WP_Post $post */ public function update_data($post_id, WP_Post $post) { $user_membership = wc_memberships_get_user_membership($post); // Update start date $start_date = isset($_POST['_start_date']) && $_POST['_start_date'] ? date('Y-m-d H:i:s', strtotime($_POST['_start_date'])) : ''; update_post_meta($post_id, '_start_date', $start_date); // Update end date $end_date = isset($_POST['_end_date']) && $_POST['_end_date'] ? date('Y-m-d H:i:s', strtotime($_POST['_end_date'])) : ''; $previous_end_date = $user_membership->get_end_date(); // If end date was set to a past date, automatically set status to expired if ($previous_end_date != $end_date && strtotime($end_date) <= current_time('timestamp')) { $user_membership->update_status('expired'); } else { if ($previous_end_date == $end_date && strtotime($end_date) <= current_time('timestamp')) { if (in_array($user_membership->get_status(), array('active', 'free_trial', 'complimentary'))) { $end_date = ''; } } else { if (strtotime($end_date) > current_time('timestamp') && 'expired' == $user_membership->get_status()) { $end_date = date('Y-m-d H:i:s', strtotime('midnight', current_time('timestamp'))); } } } $user_membership->set_end_date($end_date); }
/** * Grant a user access to this plan from a purchase * * @since 1.0.0 * @param int $user_id User ID * @param int $product_id Product ID * @param int $order_id Order ID * @return int|null New/Existing User Membership ID or null on failure */ public function grant_access_from_purchase($user_id, $product_id, $order_id) { $user_membership_id = null; $action = 'create'; // Check if user is perhaps a member, but membership is expired/cancelled if (wc_memberships_is_user_member($user_id, $this->get_id())) { $user_membership = wc_memberships_get_user_membership($user_id, $this->get_id()); $user_membership_id = $user_membership->get_id(); // Do not allow the same order to renew or reactivate the membership. This // prevents admins changing order statuses from extending/reactivating the // membership. $order_ids = get_post_meta($user_membership_id, '_order_id'); if (!empty($order_ids) && in_array($order_id, $order_ids)) { return null; } // Otherwise... continue as usual $action = 'reactivate'; if (wc_memberships_is_user_active_member($user_id, $this->get_id())) { /** * Filter whether an already active membership will be renewed * * @since 1.0.0 * @param bool $renew * @param WC_Memberships_Membership_Plan $plan * @param array $args */ $renew_membership = apply_filters('wc_memberships_renew_membership', (bool) $this->get_access_length_amount(), $this, array('user_id' => $user_id, 'product_id' => $product_id, 'order_id' => $order_id)); if (!$renew_membership) { return null; } $action = 'renew'; } } // Create/update the user membership $user_membership = wc_memberships_create_user_membership(array('user_membership_id' => $user_membership_id, 'user_id' => $user_id, 'product_id' => $product_id, 'order_id' => $order_id, 'plan_id' => $this->get_id()), $action); // Add membership note $product = wc_get_product($product_id); $order = wc_get_order($order_id); $user_membership->add_note(sprintf(__('Membership access granted from purchasing %s (Order %s)'), $product->get_title(), $order->get_order_number())); /** * Fires after a user has been granted membership access from a purchase * * @since 1.0.0 * @param WC_Memberships_Membership_Plan $membership_plan The plan that user was granted access to * @param array $args */ do_action('wc_memberships_grant_membership_access_from_purchase', $this, array('user_id' => $user_id, 'product_id' => $product_id, 'order_id' => $order_id, 'user_membership_id' => $user_membership->get_id())); return $user_membership->get_id(); }