/** * Get a list of products that grant access to a piece of content * * @since 1.0.0 * @param int $post_id * @param string $rule_type * @return array|null */ private function get_products_that_grant_access($post_id = null, $rule_type = null) { // Default to the 'current' post if (!$post_id) { global $post; $post_id = $post->ID; } // Get applied rules if ('purchasing_discount' == $rule_type) { $rules = wc_memberships()->rules->get_product_purchasing_discount_rules($post_id); } else { if (in_array(get_post_type($post_id), array('product', 'product_variation'))) { $rules = wc_memberships()->rules->get_the_product_restriction_rules($post_id); } else { $rules = wc_memberships()->rules->get_post_content_restriction_rules($post_id); } } // Find products that grant access $processed_plans = array(); // holder for membership plans that have been processed already $products = array(); foreach ($rules as $rule) { // Skip further checks if this membership plan has already been processed if (in_array($rule->get_membership_plan_id(), $processed_plans)) { continue; } $plan = wc_memberships_get_membership_plan($rule->get_membership_plan_id()); if ($plan && $plan->has_products()) { foreach ($plan->get_product_ids() as $product_id) { $products[] = $product_id; } } // Mark this plan as processed, we do not need look into it any further, // because we already know if it has any products that grant access or not. $processed_plans[] = $rule->get_membership_plan_id(); } return !empty($products) ? $products : null; }
/** * 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; }
/** * View site as a member of a particular plan * * @since 1.0.0 */ public function view_as_member() { if (empty($_REQUEST['post'])) { return; } // Get the plan post ID $id = isset($_REQUEST['post']) ? absint($_REQUEST['post']) : ''; check_admin_referer('wc-memberships-view-as-member-of_' . $id); $plan = wc_memberships_get_membership_plan($id); // Bail out if plan could not be determined if (!$id || !$plan) { return; } // Create a temporary user $username = uniqid('wcm_'); /** * Filter temporary user data * * Allows adjusting the data for a temporary user, which is * created to allow viewing the site as a member of a particular * membership plan * * @since 1.0.0 * @param array $data * @param WC_Memberships_Membership_Plan $plan */ $temp_user_data = apply_filters('wc_memberships_temporary_user_data', array('user_login' => $username, 'user_pass' => uniqid('wcmp_'), 'user_email' => $username . '@.example.com', 'first_name' => sprintf(__('%s Plan', WC_Memberships::TEXT_DOMAIN), $plan->get_name()), 'last_name' => __('Test User', WC_Memberships::TEXT_DOMAIN), 'description' => sprintf(__("A temporary user created for testing the %s plan membership. If you don't use it, feel free to delete this user."), $plan->get_name()), 'role' => 'customer'), $plan); $user_id = wp_insert_user($temp_user_data); if (is_wp_error($user_id)) { return; } // Set a temporary value in DB indicating which temporary user has been created for the current user set_transient('wc_memberships_user_' . get_current_user_id() . '_viewing_as', $user_id, YEAR_IN_SECONDS); update_user_meta($user_id, '_wc_memberships_temp_user', 1); // Create user membership $membership_id = wp_insert_post(array('post_type' => 'wc_user_membership', 'post_parent' => $plan->get_id(), 'post_author' => $user_id, 'post_status' => 'wcm-active')); // Set membership start date to now update_post_meta($membership_id, '_start_date', current_time('mysql', true)); $user = get_user_by('id', $user_id); // Now switch to that user $link = add_query_arg(array('action' => 'switch_to_user', 'user_id' => $user->ID, '_wpnonce' => wp_create_nonce("switch_to_user_{$user->ID}")), wp_login_url()); wp_redirect($link); exit; }
/** * Get the plan object * * @since 1.0.0 * @return WC_Memberships_User_Membership Instance of WC_Memberships_User_Membership */ public function get_plan() { if (!$this->plan) { $this->plan = wc_memberships_get_membership_plan($this->get_plan_id()); } return $this->plan; }
/** * Check if the membership plan has at least one subscription product that grants access * * @since 1.0.0 * @param int $plan_id Membership Plan ID * @return bool True, if has a subscription product, false otherwise */ public function has_membership_plan_subscription($plan_id) { if (!isset($this->_has_membership_plan_subscription[$plan_id])) { $plan = wc_memberships_get_membership_plan($plan_id); $product_ids = $plan->get_product_ids(); $product_ids = !empty($product_ids) ? array_map('absint', $product_ids) : null; $this->_has_membership_plan_subscription[$plan_id] = false; if (!empty($product_ids)) { foreach ($product_ids as $product_id) { if (!is_numeric($product_id) || !$product_id) { continue; } $product = wc_get_product($product_id); if (!$product) { continue; } if ($product->is_type(array('subscription', 'subscription_variation', 'variable-subscription'))) { $this->_has_membership_plan_subscription[$plan_id] = true; break; } } } } return $this->_has_membership_plan_subscription[$plan_id]; }
/** * Get user's membership * Supports getting user membership by membership ID, Post object * or a combination of the user ID and membership plan id/slug/Post object. * * If no $id is provided, defaults to getting the membership for the current user. * * @since 1.0.0 * @param mixed $id Optional. Post object or post ID of the user membership, or user ID * @param mixed $plan Optional. Membership Plan slug, post object or related post ID * @return WC_Memberships_User_Membership|bool false on failure */ public function get_user_membership($id = null, $plan = null) { // If a plan is provided, try to find user membership using user ID + plan ID if ($plan) { $user_id = $id ? $id : get_current_user_id(); $membership_plan = wc_memberships_get_membership_plan($plan); // Bail out if no user ID or membership plan if (!$user_id || !$membership_plan) { return false; } $args = array('author' => $user_id, 'post_type' => 'wc_user_membership', 'post_parent' => $membership_plan->get_id(), 'post_status' => 'any'); $user_memberships = get_posts($args); $post = !empty($user_memberships) ? $user_memberships[0] : null; } else { $post = $id; // Get from globals if (false === $post) { $post = $GLOBALS['post']; } elseif (is_numeric($post)) { $post = get_post($post); } elseif ($post instanceof WC_Memberships_User_Membership) { $post = get_post($post->get_id()); } elseif (!$post instanceof WP_Post) { $post = false; } } // If no acceptable post is found, bail out if (!$post || 'wc_user_membership' !== get_post_type($post)) { return false; } return new WC_Memberships_User_Membership($post); }
/** * 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; }
/** * Display the membership data meta box * * @param WP_Post $post * @since 1.0.0 */ public function output(WP_Post $post) { global $post; $membership_plan = wc_memberships_get_membership_plan($post); // Place post types and taxonomies into separate option groups // so that they are easier to distinguish visually. $content_restriction_content_type_options = array('post_types' => array(), 'taxonomies' => array()); // We need to prefix post_type/taxonomy names (values), so that // if a post type and taxonomy share a name, we can still distinguish // between them foreach (wc_memberships()->admin->get_valid_post_types_for_content_restriction() as $post_type_name => $post_type) { $content_restriction_content_type_options['post_types']['post_type|' . $post_type_name] = $post_type; } foreach (wc_memberships()->admin->get_valid_taxonomies_for_content_restriction() as $taxonomy_name => $taxonomy) { $content_restriction_content_type_options['taxonomies']['taxonomy|' . $taxonomy_name] = $taxonomy; } // Prepare access_length period toggler options $access_length_period_toggler_options = array('unlimited' => __('unlimited', WC_Memberships::TEXT_DOMAIN), 'specific' => __('specify a length', WC_Memberships::TEXT_DOMAIN)); // Prepare access_schedule period toggler options $access_schedule_period_toggler_options = array('immediate' => __('immediately', WC_Memberships::TEXT_DOMAIN), 'specific' => __('specify a time', WC_Memberships::TEXT_DOMAIN)); $period_options = array('days' => __('day(s)', WC_Memberships::TEXT_DOMAIN), 'weeks' => __('week(s)', WC_Memberships::TEXT_DOMAIN), 'months' => __('month(s)', WC_Memberships::TEXT_DOMAIN), 'years' => __('year(s)', WC_Memberships::TEXT_DOMAIN)); // Get applied content restriction rules $content_restriction_rules = $membership_plan->get_content_restriction_rules(); // Add empty option to create a HTML template for new rules $content_restriction_rules['__INDEX__'] = new WC_Memberships_Membership_Plan_Rule(array('rule_type' => 'content_restriction', 'membership_plan_id' => $post->ID, 'id' => '', 'content_type' => '', 'content_type_name' => '', 'object_ids' => array(), 'access_schedule' => 'immediate', 'access_schedule_exclude_trial' => 'no')); // Prepare product content type options $post_type_product = get_post_type_object('product'); $product_restriction_content_type_options = $purchasing_discount_content_type_options = array('post_types' => array('post_type|product' => $post_type_product), 'taxonomies' => array()); // prepare product restriction access_type options $product_restriction_access_type_options = array('view' => __('View', WC_Memberships::TEXT_DOMAIN), 'purchase' => __('Purchase', WC_Memberships::TEXT_DOMAIN)); foreach (wc_memberships()->admin->get_valid_taxonomies_for_product_restriction() as $taxonomy_name => $taxonomy) { $product_restriction_content_type_options['taxonomies']['taxonomy|' . $taxonomy_name] = $taxonomy; } foreach (wc_memberships()->admin->get_valid_taxonomies_for_purchasing_discounts() as $taxonomy_name => $taxonomy) { $purchasing_discount_content_type_options['taxonomies']['taxonomy|' . $taxonomy_name] = $taxonomy; } // Get applied product restriction rules $product_restriction_rules = $membership_plan->get_product_restriction_rules(); // Add empty option to create a HTML template for new rules $product_restriction_rules['__INDEX__'] = new WC_Memberships_Membership_Plan_Rule(array('rule_type' => 'product_restriction', 'membership_plan_id' => $post->ID, 'id' => '', 'content_type' => '', 'content_type_name' => '', 'object_ids' => array(), 'access_type' => '', 'access_schedule' => 'immediate', 'access_schedule_exclude_trial' => 'no')); // prepare product restriction access_type options $purchasing_discount_type_options = array('percentage' => '%', 'amount' => '$'); // Get applied product restriction rules $purchasing_discount_rules = $membership_plan->get_purchasing_discount_rules(); // Add empty option to create a HTML template for new rules $purchasing_discount_rules['__INDEX__'] = new WC_Memberships_Membership_Plan_Rule(array('rule_type' => 'purchasing_discount', 'membership_plan_id' => $post->ID, 'id' => '', 'content_type' => '', 'content_type_name' => '', 'object_ids' => array(), 'discount_type' => '', 'discount_amount' => '', 'active' => '')); ?> <div class="panel-wrap data"> <?php if (!SV_WC_Plugin_Compatibility::is_wc_version_gte_2_3()) { ?> <div class="wc-tabs-back"></div> <?php } ?> <ul class="membership_plan_data_tabs wc-tabs"> <?php /** * Filter membership plan data tabs * * @since 1.0.0 * @param array $tabs Associative array of membership plan tabs */ $membership_plan_data_tabs = apply_filters('wc_membership_plan_data_tabs', array('general' => array('label' => __('General', WC_Memberships::TEXT_DOMAIN), 'target' => 'membership-plan-data-general', 'class' => array('active')), 'restrict_content' => array('label' => __('Restrict Content', WC_Memberships::TEXT_DOMAIN), 'target' => 'membership-plan-data-restrict-content'), 'restrict_products' => array('label' => __('Restrict Products', WC_Memberships::TEXT_DOMAIN), 'target' => 'membership-plan-data-restrict-products'), 'purchasing_discounts' => array('label' => __('Purchasing Discounts', WC_Memberships::TEXT_DOMAIN), 'target' => 'membership-plan-data-purchasing-discounts'))); foreach ($membership_plan_data_tabs as $key => $tab) { $class = isset($tab['class']) ? $tab['class'] : array(); ?> <li class="<?php echo sanitize_html_class($key); ?> _options <?php echo sanitize_html_class($key); ?> _tab <?php echo implode(' ', array_map('sanitize_html_class', $class)); ?> "> <a href="#<?php echo esc_attr($tab['target']); ?> "><?php echo esc_html($tab['label']); ?> </a> </li><?php } /** * Fires after the membership plan write panel tabs are displayed * * @since 1.0.0 */ do_action('wc_membership_plan_write_panel_tabs'); ?> </ul> <div id="membership-plan-data-general" class="panel woocommerce_options_panel"><?php echo '<div class="options_group">'; // Slug woocommerce_wp_text_input(array('id' => 'post_name', 'label' => __('Slug', WC_Memberships::TEXT_DOMAIN), 'value' => $post->post_name)); echo '</div>'; echo '<div class="options_group">'; ?> <p class="form-field"><label for="_product_ids"><?php esc_html_e('Grant Access to people who purchase:', WC_Memberships::TEXT_DOMAIN); ?> </label> <?php if (SV_WC_Plugin_Compatibility::is_wc_version_gte_2_3()) { ?> <input type="hidden" id="_product_ids" name="_product_ids" class="js-ajax-select-products" style="width: 50%;" data-placeholder="<?php esc_attr_e('Search for a product…', WC_Memberships::TEXT_DOMAIN); ?> " data-multiple="true" data-selected="<?php $product_ids = array_filter(array_map('absint', (array) get_post_meta($post->ID, '_product_ids', true))); $json_ids = array(); foreach ($product_ids as $product_id) { $product = wc_get_product($product_id); if (is_object($product)) { $json_ids[$product_id] = wp_kses_post(html_entity_decode($product->get_formatted_name())); } } echo esc_attr(wc_memberships()->wp_json_encode($json_ids)); ?> " value="<?php echo esc_attr(implode(',', array_keys($json_ids))); ?> " /> <?php } else { ?> <select id="_product_ids" id="_product_ids" name="_product_ids[]" class="ajax_chosen_select_products js-ajax-select-products" multiple="multiple" data-placeholder="<?php esc_attr_e('Search for a product…', WC_Memberships::TEXT_DOMAIN); ?> "> <?php if ($membership_plan->get_product_ids()) { foreach ($membership_plan->get_product_ids() as $product_id) { $product = wc_get_product($product_id); if ($product) { echo '<option value="' . esc_attr($product_id) . '" selected="selected">' . strip_tags($product->get_formatted_name()) . '</option>'; } } } ?> </select> <?php } ?> <img class="help_tip" data-tip="<?php esc_attr_e('Leave empty to only allow members you manually assign.', WC_Memberships::TEXT_DOMAIN); ?> " src="<?php echo esc_url(WC()->plugin_url()); ?> /assets/images/help.png" height="16" width="16" /> </p> <p class="form-field plan-access-length-field"> <label for="_access_length"><?php esc_html_e('Membership Length', WC_Memberships::TEXT_DOMAIN); ?> </label> <span class="plan-access-length-selectors"> <?php $current_access_length = $membership_plan->get_access_length() ? 'specific' : 'unlimited'; ?> <?php foreach ($access_length_period_toggler_options as $value => $label) { ?> <label class="label-radio"> <input type="radio" name="_access_length" class="js-access-length-period-selector js-access-length-type" value="<?php echo esc_attr($value); ?> " <?php checked($value, $current_access_length); ?> /> <?php echo esc_html($label); ?> </label> <?php } ?> <img class="help_tip" data-tip="<?php esc_attr_e('When does the membership expire?', WC_Memberships::TEXT_DOMAIN); ?> " src="<?php echo esc_url(WC()->plugin_url()); ?> /assets/images/help.png" height="16" width="16" /> </span> <span class="plan-access-length-specific js-hide-if-access-length-unlimited <?php if (!$membership_plan->get_access_length()) { ?> hide<?php } ?> "> <input type="number" min="0" name="_access_length_amount" id="_access_length_amount" value="<?php echo esc_attr($membership_plan->get_access_length_amount()); ?> " class="access_length-amount" /> <select name="_access_length_period" id="_access_length_period" class="short access_length-period js-access-length-period-selector"> <?php foreach ($period_options as $key => $label) { ?> <option value="<?php echo esc_attr($key); ?> " <?php selected($key, $membership_plan->get_access_length_period()); ?> ><?php echo esc_html($label); ?> </option> <?php } ?> </select> </span> </p> <?php echo '</div>'; /** * Fires after the membership plan general data panel is displayed * * @since 1.0.0 */ do_action('wc_membership_plan_options_membership_plan_data_general'); ?> </div><!-- //#membership-plan-data-general --> <div id="membership-plan-data-restrict-content" class="panel woocommerce_options_panel"> <div class="table-wrap"> <?php require wc_memberships()->get_plugin_path() . '/includes/admin/meta-boxes/views/html-content-restriction-rules.php'; ?> </div> <?php if ($public_posts = wc_memberships()->rules->get_public_posts()) { ?> <p><?php printf(__('These posts are public, and will be excluded from all restriction rules: %s', WC_Memberships::TEXT_DOMAIN), wc_memberships()->admin_list_post_links($public_posts)); ?> </p> <?php } ?> <?php /** * Fires after the membership plan content restriction panel is displayed * * @since 1.0.0 */ do_action('wc_membership_plan_options_membership_plan_data_restrict_content'); ?> </div><!-- //#membership-plan-data-restrict-content --> <div id="membership-plan-data-restrict-products" class="panel woocommerce_options_panel"> <div class="table-wrap"> <?php require wc_memberships()->get_plugin_path() . '/includes/admin/meta-boxes/views/html-product-restriction-rules.php'; ?> </div> <?php if ($public_products = wc_memberships()->rules->get_public_products()) { ?> <p><?php printf(__('These products are public, and will be excluded from all restriction rules: %s', WC_Memberships::TEXT_DOMAIN), wc_memberships()->admin_list_post_links($public_products)); ?> </p> <?php } ?> <?php /** * Fires after the membership plan product restriction panel is displayed * * @since 1.0.0 */ do_action('wc_membership_plan_options_membership_plan_data_restrict_products'); ?> </div><!-- //#membership-plan-data-restrict-products --> <div id="membership-plan-data-purchasing-discounts" class="panel woocommerce_options_panel"> <div class="table-wrap"> <?php require wc_memberships()->get_plugin_path() . '/includes/admin/meta-boxes/views/html-purchasing-discount-rules.php'; ?> </div> <?php /** * Fires after the membership plan purchasing discounts panel is displayed * * @since 1.0.0 */ do_action('wc_membership_plan_options_membership_plan_data_purchasing_discounts'); ?> </div><!-- //#membership-plan-data-purchase-discounts --> <?php /** * Fires after the membership plan data panels are displayed * * @since 1.0.0 */ do_action('wc_membership_plan_data_panels'); ?> <div class="clear"></div> </div><!-- //.panel-wrap --> <?php }
/** * Get all membership plans * * @since 1.0.0 * @param array $args Optional array of arguments. Same as for get_posts. * @return array $plans Array of membership plans */ public function get_membership_plans($args = array()) { $defaults = array('posts_per_page' => -1); $args = wp_parse_args($args, $defaults); $args['post_type'] = 'wc_membership_plan'; // Unique key for caching the applied rule results $cache_key = http_build_query($args); if (!isset($this->membership_plans[$cache_key])) { $membership_plan_posts = get_posts($args); $this->membership_plans[$cache_key] = array(); if (!empty($membership_plan_posts)) { foreach ($membership_plan_posts as $post) { $this->membership_plans[$cache_key][] = wc_memberships_get_membership_plan($post); } } } return $this->membership_plans[$cache_key]; }
/** * 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; }
/** * Grant access to a membership plan * * @since 1.0.0 */ public function grant_access_to_membership() { global $wpdb; if (empty($_REQUEST['post'])) { return; } // Get the ID $plan_id = isset($_REQUEST['post']) ? absint($_REQUEST['post']) : ''; check_admin_referer('wc-memberships-grant-access-plan_' . $plan_id); $plan = wc_memberships_get_membership_plan($plan_id); $redirect_to = get_edit_post_link($plan_id, 'redirect'); $product_ids = $plan->get_product_ids(); $grant_count = 0; if (!empty($product_ids)) { foreach ($product_ids as $product_id) { $sql = "SELECT order_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE meta_key = '_product_id' AND meta_value = {$product_id} ) AND order_item_type = 'line_item'"; $order_ids = $wpdb->get_col($sql); if (empty($order_ids)) { continue; } foreach ($order_ids as $order_id) { $order = wc_get_order($order_id); if (!$order) { continue; } /** * Filter the array of valid order statuses that grant access * * Allows actors to include additional custom order statuses that * should grant access when the admin uses the "grant previous purchases access" * action * * @since 1.0.0 * @param array $valid_order_statuses_for_grant array of order statuses * @param object $plan the associated membership plan object */ $valid_order_statuses_for_grant = apply_filters('wc_memberships_grant_access_from_existing_purchase_order_statuses', array('processing', 'completed'), $plan); // skip if purchase doesn't have a valid status if (!$order->has_status($valid_order_statuses_for_grant)) { continue; } $user_id = $order->get_user_id(); // Skip if guest purchase or user is already a member if (!$user_id || wc_memberships_is_user_member($user_id, $plan_id)) { continue; } /** * Filter whether an existing purchase of the product should grant access * to the membership plan or not. * * Allows plugins to override if a previously purchased product should * retroactively grant access to a membership plan or not. * * @since 1.0.0 * @param array $args */ $grant_access = apply_filters('wc_memberships_grant_access_from_existing_purchase', true, array('user_id' => $user_id, 'product_id' => $product_id, 'order_id' => $order_id)); if (!$grant_access) { continue; } // Grant access $result = $plan->grant_access_from_purchase($user_id, $product_id, $order_id); if ($result) { $grant_count++; } } } } // Add admin message if ($grant_count) { $message = sprintf(_n('%d customer was granted access from existing purchases.', '%d customers were granted access from existing purchases', $grant_count, WC_Memberships::TEXT_DOMAIN), $grant_count); } else { $message = __('No customers were granted access from existing purchases.', WC_Memberships::TEXT_DOMAIN); } wc_memberships()->admin->message_handler->add_message($message); // Redirect back to the edit screen wp_safe_redirect($redirect_to); exit; }
/** * Check if current page is restricted (works with BuddyPress who doesn't have any page/post id) * * @param string|int|array $plans Optional. The membership plan or plans to check against. * Accepts a plan slug, ID, or an array of slugs or IDs. Default: all plans. * @param string $delay * @param bool $exclude_trial */ function kmpl_wc_memberships_has_access_to_restricted_page($plans = null, $delay = null, $exclude_trial = false) { $has_access = false; $member_since = null; $access_time = null; // grant access to super users if (is_user_logged_in() && current_user_can('wc_memberships_access_all_restricted_content')) { $has_access = true; } // Convert to an array in all cases $plans = (array) $plans; // default to use all plans if no plan is specified if (empty($plans)) { $plans = wc_memberships_get_membership_plans(); } foreach ($plans as $plan_id_or_slug) { $membership_plan = wc_memberships_get_membership_plan($plan_id_or_slug); if ($membership_plan && wc_memberships_is_user_active_member(get_current_user_id(), $membership_plan->get_id())) { $has_access = true; if (!$delay && !$exclude_trial) { break; } // Determine the earliest membership for the user $user_membership = wc_memberships()->user_memberships->get_user_membership(get_current_user_id(), $membership_plan->get_id()); // Create a pseudo-rule to help applying filters $rule = new WC_Memberships_Membership_Plan_Rule(array('access_schedule_exclude_trial' => $exclude_trial ? 'yes' : 'no')); /** This filter is documented in includes/class-wc-memberships-capabilities.php **/ $from_time = apply_filters('wc_memberships_access_from_time', $user_membership->get_start_date('timestamp'), $rule, $user_membership); // If there is no time to calculate the access time from, simply // use the current time as access start time if (!$from_time) { $from_time = current_time('timestamp', true); } if (is_null($member_since) || $from_time < $member_since) { $member_since = $from_time; } } } // Add delay if ($has_access && ($delay || $exclude_trial) && $member_since) { $access_time = $member_since; // Determine access time if (strpos($delay, 'month') !== false) { $parts = explode(' ', $delay); $amount = isset($parts[1]) ? (int) $parts[0] : ''; $access_time = wc_memberships()->add_months($member_since, $amount); } else { if ($delay) { $access_time = strtotime($delay, $member_since); } } // Output or show delayed access message if ($access_time <= current_time('timestamp', true)) { $has_access = true; } else { $has_access = false; $message = __('This content is part of your membership, but not yet! You will gain access on {date}', 'woocommerce-memberships'); // Apply the deprecated filter if (has_filter('get_content_delayed_message')) { /** This filter is documented in includes/frontend/class-wc-memberships-frontend.php **/ $message = apply_filters('get_content_delayed_message', $message, null, $access_time); // Notify developers that this filter is deprecated _deprecated_function('The get_content_delayed_message filter', '1.3.1', 'wc_memberships_get_content_delayed_message'); } /** This filter is documented in includes/frontend/class-wc-memberships-frontend.php **/ $message = apply_filters('wc_memberships_get_content_delayed_message', $message, null, $access_time); $message = str_replace('{date}', date_i18n(wc_date_format(), $access_time), $message); $output = '<div class="wc-memberships-content-delayed-message">' . $message . '</div>'; echo $output; } } return $has_access; }