/includes/functions.php

  1. <?php 
  2. /**************************************************************** 
  3.   
  4. IMPORTANT. PLEASE READ. 
  5.   
  6. DO NOT EDIT THIS FILE or any other file in the /wp-content/plugins/paid-memberships-pro/ directory. 
  7. Doing so could break the PMPro plugin and/or keep you from upgrading this plugin in the future. 
  8. We regularly release updates to the plugin, including important security fixes and new features. 
  9. You want to be able to upgrade. 
  10.   
  11. If you were asked to insert code into "your functions.php file", it was meant that you edit the functions.php 
  12. in the root folder of your active theme. e.g. /wp-content/themes/twentytwelve/functions.php 
  13. You can also create a custom plugin to place customization code into. Instructions are here: 
  14. http://www.paidmembershipspro.com/2012/08/create-a-plugin-for-pmpro-customizations/ 
  15.   
  16. Further documentation for customizing Paid Memberships Pro can be found here: 
  17. http://www.paidmembershipspro.com/documentation/ 
  18.   
  19. ****************************************************************/ 
  20. if(!function_exists("sornot")) 
  21. function sornot($t, $n) 
  22. if($n == 1) 
  23. return $t; 
  24. else 
  25. return $t . "s"; 
  26.  
  27. //set up wpdb for the tables we need 
  28. function pmpro_setDBTables() 
  29. global $wpdb; 
  30. $wpdb->hide_errors(); 
  31. $wpdb->pmpro_membership_levels = $wpdb->prefix . 'pmpro_membership_levels'; 
  32. $wpdb->pmpro_memberships_users = $wpdb->prefix . 'pmpro_memberships_users'; 
  33. $wpdb->pmpro_memberships_categories = $wpdb->prefix . 'pmpro_memberships_categories'; 
  34. $wpdb->pmpro_memberships_pages = $wpdb->prefix . 'pmpro_memberships_pages'; 
  35. $wpdb->pmpro_membership_orders = $wpdb->prefix . 'pmpro_membership_orders'; 
  36. $wpdb->pmpro_discount_codes = $wpdb->prefix . 'pmpro_discount_codes'; 
  37. $wpdb->pmpro_discount_codes_levels = $wpdb->prefix . 'pmpro_discount_codes_levels'; 
  38. $wpdb->pmpro_discount_codes_uses = $wpdb->prefix . 'pmpro_discount_codes_uses'; 
  39. $wpdb->pmpro_membership_levelmeta = $wpdb->prefix . 'pmpro_membership_levelmeta'; 
  40. pmpro_setDBTables(); 
  41.  
  42. //from: http://stackoverflow.com/questions/5266945/wordpress-how-detect-if-current-page-is-the-login-page/5892694#5892694 
  43. function pmpro_is_login_page() { 
  44. return (in_array($GLOBALS['pagenow'], array('wp-login.php', 'wp-register.php')) || is_page("login")); 
  45.  
  46. //thanks: http://wordpress.org/support/topic/is_plugin_active 
  47. function pmpro_is_plugin_active( $plugin ) { 
  48. return in_array( $plugin, (array) get_option( 'active_plugins', array() ) ); 
  49.  
  50. //scraping - override n if you have more than 1 group of matches and don't want the first group 
  51. function pmpro_getMatches($p, $s, $firstvalue = FALSE, $n = 1) 
  52. $ok = preg_match_all($p, $s, $matches); 
  53.  
  54. if(!$ok) 
  55. return false; 
  56. else 
  57. if($firstvalue) 
  58. return $matches[$n][0]; 
  59. else 
  60. return $matches[$n]; 
  61.  
  62. function pmpro_br2nl($text, $tags = "br") 
  63. if(!is_array($tags)) 
  64. $tags = explode(" ", $tags); 
  65.  
  66. foreach($tags as $tag) 
  67. $text = preg_replace("/<{$tag}[^>]*>/", "\n", $text); 
  68. $text = preg_replace("/<\/{$tag}[^>]*>/", "\n", $text); 
  69.  
  70. return($text); 
  71.  
  72. function pmpro_getOption($s, $force = false) 
  73. if(get_option("pmpro_" . $s)) 
  74. return get_option("pmpro_" . $s); 
  75. else 
  76. return ""; 
  77.  
  78. function pmpro_setOption($s, $v = NULL) 
  79. //no value is given, set v to the p var 
  80. if($v === NULL && isset($_POST[$s])) 
  81. $v = $_POST[$s]; 
  82.  
  83. if(is_array($v)) 
  84. $v = implode(", ", $v); 
  85. else 
  86. $v = trim($v); 
  87.  
  88. return update_option("pmpro_" . $s, $v); 
  89.  
  90. function pmpro_get_slug($post_id) 
  91. global $pmpro_slugs, $wpdb; 
  92.  
  93. //make sure post id is int for security 
  94. $post_id = intval($post_id); 
  95.  
  96. if(!$pmpro_slugs[$post_id]) 
  97. $pmpro_slugs[$post_id] = $wpdb->get_var("SELECT post_name FROM $wpdb->posts WHERE ID = '" . $post_id . "' LIMIT 1"); 
  98.  
  99. return $pmpro_slugs[$post_id]; 
  100.  
  101. function pmpro_url($page = NULL, $querystring = "", $scheme = NULL) 
  102. global $besecure; 
  103. $besecure = apply_filters("besecure", $besecure); 
  104.  
  105. if(!$scheme && $besecure) 
  106. $scheme = "https"; 
  107. elseif(!$scheme) 
  108. $scheme = "http"; 
  109.  
  110. if(!$page) 
  111. $page = "levels"; 
  112.  
  113. global $pmpro_pages; 
  114.  
  115. //start with the permalink 
  116. $url = get_permalink($pmpro_pages[$page]); 
  117.  
  118. //WPML/etc support 
  119. if(function_exists("icl_object_id") && defined("ICL_LANGUAGE_CODE")) 
  120. $trans_id = icl_object_id($pmpro_pages[$page], "page", false, ICL_LANGUAGE_CODE); 
  121. if(!empty($trans_id)) 
  122. $url = get_permalink($trans_id); 
  123.  
  124. //figure out querystring 
  125. $querystring = str_replace("?", "", $querystring); 
  126. parse_str( $querystring, $query_args ); 
  127. $url = esc_url_raw( add_query_arg( $query_args, $url ) ); 
  128.  
  129. //figure out scheme 
  130. if(is_ssl()) 
  131. $url = str_replace("http:", "https:", $url); 
  132.  
  133. return $url; 
  134.  
  135. function pmpro_isLevelFree(&$level) 
  136. if(!empty($level) && $level->initial_payment <= 0 && $level->billing_amount <= 0 && $level->trial_amount <= 0) 
  137. return true; 
  138. else 
  139. return false; 
  140.  
  141. // Given an array of levels, will return true if all of them are free. 
  142. function pmpro_areLevelsFree($levelarr) { 
  143. if(! is_array($levelarr)) { return false; } 
  144. foreach($levelarr as $curlevel) { 
  145. if(!empty($curlevel) && ($curlevel->initial_payment > 0 || $curlevel->billing_amount > 0 || $curlevel->trial_amount > 0)) { 
  146. return false; 
  147. return true; 
  148.  
  149. function pmpro_isLevelRecurring(&$level) 
  150. if(!empty($level) && ($level->billing_amount > 0 || $level->trial_amount > 0)) 
  151. return true; 
  152. else 
  153. return false; 
  154.  
  155. function pmpro_isLevelTrial(&$level) 
  156. if(!empty($level) && !empty($level->trial_limit) && $level->trial_limit > 0) 
  157. return true; 
  158. else 
  159. return false; 
  160.  
  161. function pmpro_isLevelExpiring(&$level) 
  162. if(!empty($level) && (!empty($level->expiration_number) && $level->expiration_number > 0) || !empty($level->enddate)) 
  163. return true; 
  164. else 
  165. return false; 
  166.  
  167. /** 
  168. * Is this level expiring within one pay period 
  169. * 
  170. * @since 1.8.6.3 
  171. * 
  172. * @param object $level PMPro Level Object to test 
  173. */ 
  174. function pmpro_isLevelExpiringSoon( &$level ) { 
  175. if( !pmpro_isLevelExpiring( $level ) || empty( $level->enddate ) ) 
  176. $r = false; 
  177. else { 
  178. //days til expiration for the standard level 
  179. $standard = pmpro_getLevel( $level->id ); 
  180.  
  181. if( !empty( $standard->expiration_number ) ) { 
  182. if( $standard->expiration_period == 'Day' ) 
  183. $days = $level->expiration_number; 
  184. elseif( $standard->expiration_period == 'Week' ) 
  185. $days = $level->expiration_number * 7; 
  186. elseif( $standard->expiration_period == 'Month' ) 
  187. $days = $level->expiration_number * 30; 
  188. elseif( $standard->expiration_period == 'Year' ) 
  189. $days = $level->expiration_number * 365; 
  190. else 
  191. $days = 30; 
  192.  
  193. //are we within the days til expiration? 
  194. $now = current_time('timestamp'); 
  195.  
  196. if( $now + ($days*3600*24) >= $level->enddate ) 
  197. $r = true; 
  198. else 
  199. $r = false; 
  200.  
  201. //filter 
  202. $r = apply_filters('pmpro_is_level_expiring_soon', $r, $level); 
  203.  
  204. return $r; 
  205.  
  206. /** 
  207. * Loads a template from one of the default paths (PMPro plugin or theme), or from filtered path 
  208. * 
  209. * @param null $page_name - Name of the page/template 
  210. * @param string $where - `local` or `url` (whether to load from FS or over http) 
  211. * @param string $type - Type of template (valid: 'email' or 'pages', 'adminpages', 'preheader') 
  212. * @param string $ext - File extension ('php', 'html', 'htm', etc) 
  213. * @return string - The HTML for the template. 
  214. * 
  215. * TODO - Allow localized template files to be loaded? 
  216. * 
  217. * @since 1.8.9 
  218. */ 
  219. function pmpro_loadTemplate($page_name = null, $where = 'local', $type = 'pages', $ext = 'php' ) 
  220. // called from page handler shortcode 
  221. if (is_null($page_name)) 
  222. global $pmpro_page_name; 
  223. $page_name = $pmpro_page_name; 
  224.  
  225. if ($where == 'local') { 
  226. // template paths in order of priority (array gets reversed) 
  227. $default_templates = array( 
  228. PMPRO_DIR . "/{$type}/{$page_name}.{$ext}", // default plugin path 
  229. get_template_directory() . "/paid-memberships-pro/{$type}/{$page_name}.{$ext}", // parent theme 
  230. get_stylesheet_directory() . "/paid-memberships-pro/{$type}/{$page_name}.{$ext}", // child / active theme 
  231. ); 
  232. } elseif( $where == 'url' ) { 
  233. // template paths in order of priority (array gets reversed) 
  234. $default_templates = array( 
  235. PMPRO_URL . "/{$type}/{$page_name}.{$ext}", // default plugin path 
  236. get_template_directory_uri() . "/paid-memberships-pro/{$type}/{$page_name}.{$ext}", // parent theme 
  237. get_stylesheet_directory_uri() . "/paid-memberships-pro/{$type}/{$page_name}.{$ext}", // child / active theme 
  238. ); 
  239.  
  240. // Valid types: 'email', 'pages' 
  241. $templates = apply_filters("pmpro_{$type}_custom_template_path", $default_templates, $page_name, $type, $where, $ext); 
  242. $user_templates = array_diff($templates, $default_templates); 
  243.  
  244. //user specified a custom template path, so it has priority. 
  245. if (!empty($user_templates)) 
  246. $templates = $user_templates; 
  247.  
  248. //last element included in the array is the most first one we try to load 
  249. $templates = array_reverse($templates); 
  250.  
  251. // look for template file to include 
  252. ob_start(); 
  253. foreach($templates as $template_path) 
  254. {  
  255. // If loading a local file, check if it exists first 
  256. if($where == 'url' || file_exists($template_path)) 
  257. include $template_path; 
  258. break; 
  259. $template = ob_get_clean(); 
  260.  
  261. // return template content 
  262. return $template; 
  263.  
  264. function pmpro_getLevelCost(&$level, $tags = true, $short = false) 
  265. //initial payment 
  266. if(!$short) 
  267. $r = sprintf(__('The price for membership is <strong>%s</strong> now', 'paid-memberships-pro' ), pmpro_formatPrice($level->initial_payment)); 
  268. else 
  269. $r = sprintf(__('<strong>%s</strong> now', 'paid-memberships-pro' ), pmpro_formatPrice($level->initial_payment)); 
  270.  
  271. //recurring part 
  272. if($level->billing_amount != '0.00') 
  273. if($level->billing_limit > 1) 
  274. if($level->cycle_number == '1') 
  275. $r .= sprintf(__(' and then <strong>%s per %s for %d more %s</strong>.', 'paid-memberships-pro' ), pmpro_formatPrice($level->billing_amount), pmpro_translate_billing_period($level->cycle_period), $level->billing_limit, pmpro_translate_billing_period($level->cycle_period, $level->billing_limit)); 
  276. else 
  277. $r .= sprintf(__(' and then <strong>%s every %d %s for %d more payments</strong>.', 'paid-memberships-pro' ), pmpro_formatPrice($level->billing_amount), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number), $level->billing_limit); 
  278. elseif($level->billing_limit == 1) 
  279. $r .= sprintf(__(' and then <strong>%s after %d %s</strong>.', 'paid-memberships-pro' ), pmpro_formatPrice($level->billing_amount), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number)); 
  280. else 
  281. if( $level->billing_amount === $level->initial_payment ) { 
  282. if($level->cycle_number == '1') 
  283. if(!$short) 
  284. $r = sprintf(__('The price for membership is <strong>%s per %s</strong>.', 'paid-memberships-pro' ), pmpro_formatPrice($level->initial_payment), pmpro_translate_billing_period($level->cycle_period) ); 
  285. else 
  286. $r = sprintf(__('<strong>%s per %s</strong>.', 'paid-memberships-pro' ), pmpro_formatPrice($level->initial_payment), pmpro_translate_billing_period($level->cycle_period) ); 
  287. else 
  288. if(!$short) 
  289. $r = sprintf(__('The price for membership is <strong>%s every %d %s</strong>.', 'paid-memberships-pro' ), pmpro_formatPrice($level->initial_payment), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number) ); 
  290. else 
  291. $r = sprintf(__('<strong>%s every %d %s</strong>.', 'paid-memberships-pro' ), pmpro_formatPrice($level->initial_payment), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number) ); 
  292. } else { 
  293. if($level->cycle_number == '1') 
  294. $r .= sprintf(__(' and then <strong>%s per %s</strong>.', 'paid-memberships-pro' ), pmpro_formatPrice($level->billing_amount), pmpro_translate_billing_period($level->cycle_period)); 
  295. else 
  296. $r .= sprintf(__(' and then <strong>%s every %d %s</strong>.', 'paid-memberships-pro' ), pmpro_formatPrice($level->billing_amount), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number)); 
  297. else 
  298. $r .= '.'; 
  299.  
  300. //add a space 
  301. $r .= ' '; 
  302.  
  303. //trial part 
  304. if($level->trial_limit) 
  305. if($level->trial_amount == '0.00') 
  306. if($level->trial_limit == '1') 
  307. $r .= ' ' . __('After your initial payment, your first payment is Free.', 'paid-memberships-pro' ); 
  308. else 
  309. $r .= ' ' . sprintf(__('After your initial payment, your first %d payments are Free.', 'paid-memberships-pro' ), $level->trial_limit); 
  310. else 
  311. if($level->trial_limit == '1') 
  312. $r .= ' ' . sprintf(__('After your initial payment, your first payment will cost %s.', 'paid-memberships-pro' ), pmpro_formatPrice($level->trial_amount)); 
  313. else 
  314. $r .= ' ' . sprintf(__('After your initial payment, your first %d payments will cost %s.', 'paid-memberships-pro' ), $level->trial_limit, pmpro_formatPrice($level->trial_amount)); 
  315.  
  316. //taxes part 
  317. $tax_state = pmpro_getOption("tax_state"); 
  318. $tax_rate = pmpro_getOption("tax_rate"); 
  319.  
  320. if($tax_state && $tax_rate && !pmpro_isLevelFree($level)) 
  321. $r .= sprintf(__('Customers in %s will be charged %s%% tax.', 'paid-memberships-pro' ), $tax_state, round($tax_rate * 100, 2)); 
  322.  
  323. if(!$tags) 
  324. $r = strip_tags($r); 
  325.  
  326. $r = apply_filters("pmpro_level_cost_text", $r, $level, $tags, $short); //passing $tags and $short since v1.8 
  327. return $r; 
  328.  
  329. // Similar to pmpro_getLevelCost, but loops through all levels in the incoming array and puts it all together. 
  330. function pmpro_getLevelsCost(&$levels, $tags = true, $short = false) 
  331. // let's build the array to work from to consolidate recurring info. 
  332. // recurpmts[cycle_period][cycle_number][billing_limit] = total_amount 
  333. $initpmt = 0; 
  334. $recurpmts = array(); 
  335. $trialperiods = 0; 
  336. foreach($levels as $curlevel) { 
  337. $initpmt += $curlevel->initial_payment; 
  338. if($curlevel->billing_amount != '0.00') { 
  339. if(array_key_exists($curlevel->cycle_period, $recurpmts)) { 
  340. if(array_key_exists($curlevel->cycle_number, $recurpmts[$curlevel->cycle_period])) { 
  341. if(array_key_exists($curlevel->billing_limit, $recurpmts[$curlevel->cycle_period][$curlevel->cycle_number])) { 
  342. $recurpmts[$curlevel->cycle_period][$curlevel->cycle_number][$curlevel->billing_limit] += $curlevel->billing_amount; 
  343. } else { 
  344. $recurpmts[$curlevel->cycle_period][$curlevel->cycle_number][$curlevel->billing_limit] = $curlevel->billing_amount; 
  345. } else { 
  346. $recurpmts[$curlevel->cycle_period][$curlevel->cycle_number] = array(); 
  347. $recurpmts[$curlevel->cycle_period][$curlevel->cycle_number][$curlevel->billing_limit] = $curlevel->billing_amount; 
  348. } else { 
  349. $recurpmts[$curlevel->cycle_period] = array(); 
  350. $recurpmts[$curlevel->cycle_period][$curlevel->cycle_number] = array(); 
  351. $recurpmts[$curlevel->cycle_period][$curlevel->cycle_number][$curlevel->billing_limit] = $curlevel->billing_amount; 
  352. if($curlevel->trial_limit && intval($curlevel->trial_limit)>$trialperiods) { 
  353. $trialperiods = intval($curlevel->trial_limit); 
  354.  
  355. // initial payment 
  356. if(!$short) 
  357. $r = sprintf(__('The price for membership is <strong>%s</strong> now', 'paid-memberships-pro' ), pmpro_formatPrice($initpmt)); 
  358. else 
  359. $r = sprintf(__('<strong>%s</strong> now', 'paid-memberships-pro' ), pmpro_formatPrice($initpmt)); 
  360.  
  361. //recurring part 
  362. $billtextparts = array(); 
  363. if(count($recurpmts)>0) { 
  364. foreach($recurpmts as $curperiod => $curpddata) { 
  365. foreach($curpddata as $curcyclenum => $curcycledata) { 
  366. foreach($curcycledata as $curbilllimit => $curtotal) { 
  367. if($curbilllimit > 1) 
  368. if($curcyclenum == '1') 
  369. $billtextparts[] = sprintf(__('<strong>%s per %s for %d more %s</strong>', 'paid-memberships-pro' ), pmpro_formatPrice($curtotal), pmpro_translate_billing_period($curperiod), $curbilllimit, pmpro_translate_billing_period($curperiod, $curbilllimit)); 
  370. else 
  371. $billtextparts[] = sprintf(__('<strong>%s every %d %s for %d more payments</strong>', 'paid-memberships-pro' ), pmpro_formatPrice($curtotal), $curcyclenum, pmpro_translate_billing_period($curperiod, $curcyclenum), $curbilllimit); 
  372. elseif($curbilllimit == 1) 
  373. $billtextparts[] = sprintf(__('<strong>%s after %d %s</strong>', 'paid-memberships-pro' ), pmpro_formatPrice($curtotal), $curcyclenum, pmpro_translate_billing_period($curperiod, $curcyclenum)); 
  374. else 
  375. if($curcyclenum == '1') 
  376. $billtextparts[] = sprintf(__('<strong>%s every %s</strong>', 'paid-memberships-pro' ), pmpro_formatPrice($curtotal), pmpro_translate_billing_period($curperiod)); 
  377. else 
  378. $billtextparts[] = sprintf(__('<strong>%s every %d %s</strong>', 'paid-memberships-pro' ), pmpro_formatPrice($curtotal), $curcyclenum, pmpro_translate_billing_period($curperiod, $curcyclenum)); 
  379. $laststanza = array_pop($billtextparts); 
  380. if(count($billtextparts)>0) { 
  381. $r .= ", "; 
  382. $r .= implode(', ', $billtextparts); 
  383. $r .= ", and ".$laststanza."."; 
  384. } else { 
  385. $r .= "."; 
  386.  
  387.  
  388. //add a space 
  389. $r .= ' '; 
  390.  
  391. //trial part - not as detailed as the single-level counterpart. Could be improved in the future. 
  392. if($trialperiods>0) { 
  393. if($trialperiods==1) { 
  394. $r .= __('Trial pricing has been applied to the first payment.', 'mmpu'); 
  395. } else { 
  396. $r .= sprintf(__('Trial pricing has been applied to the first %d payments.', 'mmpu'), $trialperiods); 
  397.  
  398. //taxes part 
  399. $tax_state = pmpro_getOption("tax_state"); 
  400. $tax_rate = pmpro_getOption("tax_rate"); 
  401.  
  402. if($tax_state && $tax_rate && !pmpro_areLevelsFree($levels)) 
  403. $r .= sprintf(__('Customers in %s will be charged %s%% tax.', 'paid-memberships-pro' ), $tax_state, round($tax_rate * 100, 2)); 
  404.  
  405. if(!$tags) 
  406. $r = strip_tags($r); 
  407.  
  408. /** 
  409. * Filter the levels cost text. Note the s in levels. Similar to pmpro_levels_cost_text 
  410. */ 
  411. $r = apply_filters("pmpro_levels_cost_text", $r, $levels, $tags, $short); 
  412. return $r; 
  413.  
  414. function pmpro_getLevelExpiration(&$level) 
  415. if($level->expiration_number) 
  416. $expiration_text = sprintf(__("Membership expires after %d %s.", 'paid-memberships-pro' ), $level->expiration_number, pmpro_translate_billing_period($level->expiration_period, $level->expiration_number)); 
  417. else 
  418. $expiration_text = ""; 
  419.  
  420. $expiration_text = apply_filters("pmpro_levels_expiration_text", $expiration_text, $level); 
  421. $expiration_text = apply_filters("pmpro_level_expiration_text", $expiration_text, $level); // Backwards compatible 
  422. return $expiration_text; 
  423.  
  424. function pmpro_getLevelsExpiration(&$levels) 
  425. $expirystrings = array(); 
  426. $ongoinglevelnum = 0; 
  427. if(!empty($levels) && !is_array($levels)) { $levels = array($levels); } elseif(empty($levels)) { $levels = array(); } 
  428. foreach($levels as $curlevel) { 
  429. if($curlevel->expiration_number) { 
  430. $expirystrings[] = sprintf(__("%s membership expires after %d %s", 'paid-memberships-pro' ), $curlevel->name, $curlevel->expiration_number, pmpro_translate_billing_period($curlevel->expiration_period, $curlevel->expiration_number)); 
  431. } else { 
  432. $ongoinglevelnum++; 
  433.  
  434. $expiration_text = ""; 
  435. if(count($expirystrings)>0) { 
  436. $laststanza = array_pop($expirystrings); 
  437. $expiration_text = implode(', ', $expirystrings); 
  438. if(count($expirystrings)>0) { $expiration_text .= ", and "; } 
  439. $expiration_text .= $laststanza; 
  440. $expiration_text .= ". "; 
  441. if($ongoinglevelnum>0) { 
  442. $expiration_text .= "The remaining membership"; 
  443. if($ongoinglevelnum>1) { $expiration_text .= "s are"; } else { $expiration_text .= " is"; } 
  444. $expiration_text .= " ongoing."; 
  445.  
  446. /** 
  447. * Filter the levels expiration text. Note the s in levels. Similar to pmpro_levels_expiration_text 
  448. */ 
  449. $expiration_text = apply_filters("pmpro_levels_expiration_text", $expiration_text, $levels); 
  450. $expiration_text = apply_filters("pmpro_level_expiration_text", $expiration_text, $levels); // Backwards compatible 
  451. return $expiration_text; 
  452.  
  453. /** 
  454. * pmpro_membership_level Meta Functions 
  455. * 
  456. * @ssince 1.8.6.5 
  457. */ 
  458. function add_pmpro_membership_level_meta($level_id, $meta_key, $meta_value, $unique = false) {  
  459. return add_metadata('pmpro_membership_level', $level_id, $meta_key, $meta_value, $unique); 
  460.  
  461. function get_pmpro_membership_level_meta($level_id, $key, $single = false) { 
  462. return get_metadata('pmpro_membership_level', $level_id, $key, $single); 
  463.  
  464. function update_pmpro_membership_level_meta($level_id, $meta_key, $meta_value, $prev_value = '') {  
  465. return update_metadata('pmpro_membership_level', $level_id, $meta_key, $meta_value, $prev_value); 
  466.  
  467. function delete_pmpro_membership_level_meta($level_id, $meta_key, $meta_value = '') {  
  468. return delete_metadata('pmpro_membership_level', $level_id, $meta_key, $meta_value); 
  469.  
  470. function pmpro_hideAds() 
  471. global $pmpro_display_ads; 
  472. return !$pmpro_display_ads; 
  473.  
  474. function pmpro_displayAds() 
  475. global $pmpro_display_ads; 
  476. return $pmpro_display_ads; 
  477.  
  478. function pmpro_next_payment($user_id = NULL, $order_status = "success", $format = "timestamp") 
  479. global $wpdb, $current_user; 
  480. if(!$user_id) 
  481. $user_id = $current_user->ID; 
  482.  
  483. if(!$user_id) 
  484. $r = false; 
  485. else 
  486. //get last order 
  487. $order = new MemberOrder(); 
  488. $order->getLastMemberOrder($user_id, $order_status); 
  489.  
  490. //get current membership level 
  491. $level = pmpro_getMembershipLevelForUser($user_id); 
  492.  
  493. if(!empty($order) && !empty($order->id) && !empty($level) && !empty($level->id) && !empty($level->cycle_number)) 
  494. //last payment date 
  495. $lastdate = date_i18n("Y-m-d", $order->timestamp); 
  496.  
  497. //next payment date 
  498. $nextdate = $wpdb->get_var("SELECT UNIX_TIMESTAMP('" . $lastdate . "' + INTERVAL " . $level->cycle_number . " " . $level->cycle_period . ")"); 
  499.  
  500. $r = $nextdate; 
  501. else 
  502. //no order or level found, or level was not recurring 
  503. $r = false; 
  504.  
  505. /** 
  506. * Filter the next payment date. 
  507. * 
  508. * @since 1.8.5 
  509. * 
  510. * @param mixed $r false or the next payment date timestamp 
  511. * @param int $user_id The user id to get the next payment date for 
  512. * @param string $order_status Status or array of statuses to find the last order based on. 
  513. */ 
  514. $r = apply_filters('pmpro_next_payment', $r, $user_id, $order_status); 
  515.  
  516. //return in desired format 
  517. if($r === false) 
  518. return false; //always return false when no date found 
  519. elseif($format == "timestamp") 
  520. return $r; 
  521. elseif($format == "date_format") 
  522. return date_i18n(get_option('date_format'), $r); 
  523. else 
  524. return date_i18n($format, $r); //assume a PHP date format  
  525.  
  526. if(!function_exists("last4")) 
  527. function last4($t) 
  528. return substr($t, strlen($t) - 4, 4); 
  529.  
  530. if(!function_exists("hideCardNumber")) 
  531. function hideCardNumber($c, $dashes = true) 
  532. if($c) 
  533. if($dashes) 
  534. return "XXXX-XXXX-XXXX-" . substr($c, strlen($c) - 4, 4); 
  535. else 
  536. return "XXXXXXXXXXXX" . substr($c, strlen($c) - 4, 4); 
  537. else 
  538. return ""; 
  539.  
  540. //check for existing functions since we didn't use a prefix for this function 
  541. if(!function_exists("cleanPhone")) 
  542. /** 
  543. * Function to remove special characters from a phone number. 
  544. * NOTE: Could probably replace with preg_replace("[^0-9]", "", $phone) 
  545. * 
  546. * @since 1.0 
  547. * 
  548. * @param string $phone The phone number to clean. 
  549. */ 
  550. function cleanPhone($phone) 
  551. //if a + is passed, just pass it along 
  552. if(strpos($phone, "+") !== false) 
  553. return $phone; 
  554. //clean the phone 
  555. $phone = str_replace("-", "", $phone); 
  556. $phone = str_replace(".", "", $phone); 
  557. $phone = str_replace("(", "", $phone); 
  558. $phone = str_replace(")", "", $phone); 
  559. $phone = str_replace(" ", "", $phone); 
  560. return $phone; 
  561.  
  562. //check for existing functions since we didn't use a prefix for this function 
  563. if(!function_exists("formatPhone")) 
  564. /** 
  565. * Function to format a phone number. 
  566. * 
  567. * @since 1.0 
  568. * 
  569. * @param string $phone The phone number to format. 
  570. */ 
  571. function formatPhone($phone) 
  572. $r = cleanPhone($phone); 
  573.  
  574. if(strlen($r) == 11) 
  575. $r = substr($r, 0, 1) . " (" . substr($r, 1, 3) . ") " . substr($r, 4, 3) . "-" . substr($r, 7, 4); 
  576. elseif(strlen($r) == 10) 
  577. $r = "(" . substr($r, 0, 3) . ") " . substr($r, 3, 3) . "-" . substr($r, 6, 4); 
  578. elseif(strlen($r) == 7) 
  579. $r = substr($r, 0, 3) . "-" . substr($r, 3, 4); 
  580.  
  581. /** 
  582. * Filter to do more or less cleaning of phone numbers. 
  583. * 
  584. * @since 1.8.4.4 
  585. * 
  586. * @param string $r The formatted phone number. 
  587. * @param string $phone The original phone number. 
  588. */ 
  589. return apply_filters('pmpro_format_phone', $r, $phone); 
  590.  
  591. function pmpro_showRequiresMembershipMessage() 
  592. //TODO $current_user $post_membership_levels_names are undefined variables 
  593. //get the correct message 
  594. if(is_feed()) 
  595. $content = pmpro_getOption("rsstext"); 
  596. $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content); 
  597. elseif($current_user->ID) 
  598. //not a member 
  599. $content = pmpro_getOption("nonmembertext"); 
  600. $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content); 
  601. else 
  602. //not logged in! 
  603. $content = pmpro_getOption("notloggedintext"); 
  604. $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content); 
  605.  
  606. /** 
  607. * Function to check if a user has specified membership levels. 
  608. * 
  609. * pmpro_hasMembershipLevel() checks if the passed user is a member of the passed level 
  610. * $level may either be the ID or name of the desired membership_level. (or an array of such) 
  611. * If $user_id is omitted, the value will be retrieved from $current_user. 
  612. * 
  613. * Return values: 
  614. * * Success returns boolean true. 
  615. * * Failure returns a string containing the error message. 
  616. * 
  617. * @since 1.8.5 Added 'e' option for expired members. 
  618. * @since 1.0.0 
  619. * 
  620. * @param mixed $levels The levels to check. 
  621. * @param int $user_id The user ID to check. 
  622. * 
  623. * @return bool Result of membership query. 
  624. */ 
  625. function pmpro_hasMembershipLevel($levels = NULL, $user_id = NULL) 
  626. global $current_user, $wpdb; 
  627.  
  628. $return = false; 
  629.  
  630. if(empty($user_id)) //no user_id passed, check the current user 
  631. $user_id = $current_user->ID; 
  632.  
  633. if(!empty($user_id) && is_numeric($user_id)) //get membership levels for given user 
  634. $membership_levels = pmpro_getMembershipLevelsForUser($user_id); 
  635. else 
  636. $membership_levels = NULL; //non-users don't have levels 
  637.  
  638. if($levels === "0" || $levels === 0) //if 0 was passed, return true if they have no level and false if they have any 
  639. $return = empty($membership_levels); 
  640. elseif(empty($levels)) //if no level var was passed, we're just checking if they have any level 
  641. $return = !empty($membership_levels); 
  642. else 
  643. if(!is_array($levels)) //make an array out of a single element so we can use the same code 
  644. $levels = array($levels); 
  645.  
  646. if(empty($membership_levels)) //user has no levels just check if 0, L, -1, or e was sent in one of the levels 
  647. //check for negative level 
  648. $negative_level = false; 
  649. foreach($levels as $level) { 
  650. if(intval($level) < 0) { 
  651. $negative_level = true; 
  652. break; 
  653.  
  654. //are we looking for non-members or not? 
  655. if($negative_level) 
  656. return true; //-1/etc, negative level 
  657. elseif(in_array(0, $levels, true) || in_array("0", $levels)) 
  658. $return = true; //0 level 
  659. elseif(in_array("L", $levels) || in_array("l", $levels)) 
  660. $return = (!empty($user_id) && $user_id == $current_user->ID); //L, logged in users 
  661. elseif(in_array("-L", $levels) || in_array("-l", $levels)) 
  662. $return = (empty($user_id) || $user_id != $current_user->ID); //-L, not logged in users 
  663. elseif(in_array("E", $levels) || in_array("e", $levels)) { 
  664. $sql = "SELECT id FROM $wpdb->pmpro_memberships_users WHERE user_id=$user_id AND status='expired' LIMIT 1"; 
  665. $expired = $wpdb->get_var($sql); //E, expired members 
  666. $return = !empty($expired); 
  667. else 
  668. foreach($levels as $level) 
  669. if(strtoupper($level) == "L") 
  670. //checking if user is logged in 
  671. if(!empty($user_id) && $user_id == $current_user->ID) 
  672. $return = true; 
  673. elseif(strtoupper($level) == "-L") 
  674. //checking if user is logged out 
  675. if(empty($user_id) || $user_id != $current_user->ID) 
  676. $return = true; 
  677. elseif($level === "0" || $level === 0 || strtoupper($level) === "E") 
  678. continue; //user with levels so not a "non-member" or expired 
  679. else 
  680. //checking a level id 
  681. $level_obj = pmpro_getLevel(is_numeric($level) ? abs(intval($level)) : $level); //make sure our level is in a proper format 
  682. if(empty($level_obj)) {continue;} //invalid level 
  683. $found_level = false; 
  684.  
  685. foreach($membership_levels as $membership_level) 
  686. if($membership_level->id == $level_obj->id) //found a match 
  687. $found_level = true; 
  688.  
  689. if(is_numeric($level) && intval($level) < 0 && !$found_level) //checking for the absence of this level and they don't have it 
  690. $return = true; 
  691. elseif(is_numeric($level) && intval($level) > 0 && $found_level) //checking for the presence of this level and they have it 
  692. $return = true; 
  693. elseif(!is_numeric($level)) //if a level name was passed 
  694. $return = $found_level; 
  695.  
  696. $return = apply_filters("pmpro_has_membership_level", $return, $user_id, $levels); 
  697. return $return; 
  698.  
  699. /** 
  700. * Wrapper for pmpro_changeMembershipLevel to cancel one level. 
  701. * @since 1.8.11 
  702. */ 
  703. function pmpro_cancelMembershipLevel($cancel_level, $user_id = NULL, $old_level_status = 'inactive') { 
  704. return pmpro_changeMembershipLevel(0, $user_id, $old_level_status, $cancel_level); 
  705. }  
  706.  
  707. /** 
  708. * Create, add, remove or updates the membership level of the given user to the given level. 
  709. * 
  710. * $level may either be the ID or name of the desired membership_level. 
  711. * If $user_id is omitted, the value will be retrieved from $current_user. 
  712. * 
  713. * @param int $level ID of level to set as new level, use 0 to cancel membership 
  714. * @param int $user_id ID of the user to change levels for 
  715. * @param string $old_level_status The status to set for the row in the memberships users table. (e.g. inactive, cancelled, admin_cancelled, expired) Defaults to 'inactive'. 
  716. * $param int $cancel_level If set cancel just this one level instead of all active levels (to support Multiple Memberships per User) 
  717. * 
  718. * Return values: 
  719. * Success returns boolean true. 
  720. * Failure returns boolean false. 
  721. */ 
  722. function pmpro_changeMembershipLevel($level, $user_id = NULL, $old_level_status = 'inactive', $cancel_level = NULL) 
  723. global $wpdb; 
  724. global $current_user, $pmpro_error; 
  725.  
  726. if(empty($user_id)) 
  727. $user_id = $current_user->ID; 
  728.  
  729. if(empty($user_id)) 
  730. $pmpro_error = __("User ID not found.", 'paid-memberships-pro' ); 
  731. return false; 
  732.  
  733. //make sure user id is int for security 
  734. $user_id = intval($user_id); 
  735.  
  736. if(empty($level)) //cancelling membership 
  737. $level = 0; 
  738. else if(is_array($level)) 
  739. //custom level 
  740. else 
  741. $level_obj = pmpro_getLevel($level); 
  742. if(empty($level_obj)) 
  743. $pmpro_error = __("Invalid level.", 'paid-memberships-pro' ); 
  744. return false; 
  745. $level = $level_obj->id; 
  746.  
  747. //if it's a custom level, they're changing 
  748. if(!is_array($level)) 
  749. //are they even changing? 
  750. if(pmpro_hasMembershipLevel($level, $user_id)) { 
  751. $pmpro_error = __("not changing?", 'paid-memberships-pro' ); 
  752. return false; //not changing 
  753.  
  754. //get all active membershipships for this user 
  755. $old_levels = pmpro_getMembershipLevelsForUser($user_id); 
  756.  
  757.  
  758. //get level id 
  759. if(is_array($level)) 
  760. $level_id = $level['membership_id']; //custom level 
  761. else 
  762. $level_id = $level; //just id 
  763.  
  764. /** 
  765. * Action to run before the membership level changes. 
  766. * 
  767. * @param int $level_id ID of the level changed to. 
  768. * @param int $user_id ID of the user changed. 
  769. * @param array $old_levels array of prior levels the user belonged to. 
  770. * $param int $cancel_level ID of the level being cancelled if specified 
  771. */ 
  772. do_action("pmpro_before_change_membership_level", $level_id, $user_id, $old_levels, $cancel_level); 
  773.  
  774.  
  775. //deactivate old memberships based on the old_level_status passed in (updates pmpro_memberships_users table) 
  776. $pmpro_deactivate_old_levels = true; 
  777. /** 
  778. * Filter whether old levels should be deactivated or not. This supports the MMPU addon. 
  779. * Typically you'll want to hook into pmpro_before_change_membership_level  
  780. * or pmpro_after_change_membership_level later to run your own deactivation logic. 
  781. *  
  782. * @since 1.8.11 
  783. * @var $pmpro_deactivate_old_levels bool True or false if levels should be deactivated. Defaults to true. 
  784. */ 
  785. $pmpro_deactivate_old_levels = apply_filters("pmpro_deactivate_old_levels", $pmpro_deactivate_old_levels); 
  786.  
  787. //make sure we deactivate the specified level if it's passed in 
  788. if(!empty($cancel_level)) { 
  789. $pmpro_deactivate_old_levels = true; 
  790. $new_old_levels = array(); 
  791. foreach($old_levels as $key => $old_level) { 
  792. if($old_level->id == $cancel_level) { 
  793. $new_old_levels[] = $old_levels[$key]; 
  794. break; 
  795. $old_levels = $new_old_levels; 
  796.  
  797. if($old_levels && $pmpro_deactivate_old_levels) 
  798. foreach($old_levels as $old_level) { 
  799.  
  800. $sql = "UPDATE $wpdb->pmpro_memberships_users SET `status`='$old_level_status', `enddate`='" . current_time('mysql') . "' WHERE `id`=".$old_level->subscription_id; 
  801.  
  802. if(!$wpdb->query($sql)) 
  803. $pmpro_error = __("Error interacting with database", 'paid-memberships-pro' ) . ": ".($wpdb->last_error?$wpdb->last_error:'unavailable'); 
  804.  
  805. return false; 
  806.  
  807. //should we cancel their gateway subscriptions? 
  808. if(!empty($cancel_level)) { 
  809. $pmpro_cancel_previous_subscriptions = true; //don't filter cause we're doing just the one 
  810.  
  811. $other_order_ids = $wpdb->get_col("SELECT id FROM $wpdb->pmpro_membership_orders WHERE user_id = '" . $user_id . "' AND status = 'success' AND membership_id = '" . esc_sql($cancel_level) . "' ORDER BY id DESC"); 
  812. } else { 
  813. $pmpro_cancel_previous_subscriptions = true; 
  814. if(isset($_REQUEST['cancel_membership']) && $_REQUEST['cancel_membership'] == false) 
  815. $pmpro_cancel_previous_subscriptions = false; 
  816. $pmpro_cancel_previous_subscriptions = apply_filters("pmpro_cancel_previous_subscriptions", $pmpro_cancel_previous_subscriptions); 
  817.  
  818. $other_order_ids = $wpdb->get_col("SELECT id FROM $wpdb->pmpro_membership_orders WHERE user_id = '" . $user_id . "' AND status = 'success' ORDER BY id DESC"); 
  819.  
  820. //cancel any other subscriptions they have (updates pmpro_membership_orders table) 
  821. if($pmpro_cancel_previous_subscriptions && !empty($other_order_ids)) 
  822. {  
  823. foreach($other_order_ids as $order_id) 
  824. $c_order = new MemberOrder($order_id); 
  825. $c_order->cancel(); 
  826.  
  827. if(!empty($c_order->error)) 
  828. $pmpro_error = $c_order->error; 
  829.  
  830. //insert current membership 
  831. if(!empty($level)) //are we getting a new one or just cancelling the old ones 
  832. {  
  833. //make sure the dates are in good formats 
  834. if(is_array($level)) 
  835. //Better support mySQL Strict Mode by passing a proper enum value for cycle_period 
  836. if ($level['cycle_period'] == '') { $level['cycle_period'] = 0; } 
  837.  
  838. // clean up date formatting (string/not string) 
  839. $level['startdate'] = preg_replace('/\'/', '', $level['startdate']); 
  840. $level['enddate'] = preg_replace('/\'/', '', $level['enddate']); 
  841.  
  842. $sql = $wpdb->prepare(" 
  843. INSERT INTO {$wpdb->pmpro_memberships_users} 
  844. (`user_id`, `membership_id`, `code_id`, `initial_payment`, `billing_amount`, `cycle_number`, `cycle_period`, `billing_limit`, `trial_amount`, `trial_limit`, `startdate`, `enddate`) 
  845. VALUES 
  846. ( %d, %d, %d, %s, %s, %d, %s, %d, %s, %d, %s, %s )",  
  847. $level['user_id'], // integer 
  848. $level['membership_id'], // integer 
  849. $level['code_id'], // integer 
  850. $level['initial_payment'], // float (string) 
  851. $level['billing_amount'], // float (string) 
  852. $level['cycle_number'], // integer 
  853. $level['cycle_period'], // string (enum) 
  854. $level['billing_limit'], // integer 
  855. $level['trial_amount'], // float (string) 
  856. $level['trial_limit'], // integer 
  857. $level['startdate'], // string (date) 
  858. $level['enddate'] // string (date) 
  859. ); 
  860. else 
  861. $sql = $wpdb->prepare(" 
  862. INSERT INTO {$wpdb->pmpro_memberships_users} 
  863. ( `user_id`, `membership_id`, `code_id`, `initial_payment`, `billing_amount`, `cycle_number`, `cycle_period`, `billing_limit`, `trial_amount`, `trial_limit`, `startdate`, `enddate`) 
  864. VALUES  
  865. ( %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %s, %s )",  
  866. $user_id,  
  867. $level_id,  
  868. '0',  
  869. '0',  
  870. '0',  
  871. '0',  
  872. '0',  
  873. '0',  
  874. '0',  
  875. '0',  
  876. current_time('mysql'),  
  877. '0000-00-00 00:00:00' 
  878. ); 
  879.  
  880. if( false === $wpdb->query($sql) ) 
  881. $pmpro_error = sprintf( __("Error interacting with database: %s", 'paid-memberships-pro' ), (!empty($wpdb->last_error) ? $wpdb->last_error : 'unavailable' )); 
  882. return false; 
  883. }  
  884.  
  885. //remove cached level 
  886. global $all_membership_levels; 
  887. unset($all_membership_levels[$user_id]); 
  888.  
  889. //update user data and call action 
  890. pmpro_set_current_user(); 
  891.  
  892. /** 
  893. * Action to run after the membership level changes. 
  894. * 
  895. * @param int $level_id ID of the level changed to. 
  896. * @param int $user_id ID of the user changed. 
  897. * $param int $cancel_level ID of the level being cancelled if specified. 
  898. */ 
  899. do_action("pmpro_after_change_membership_level", $level_id, $user_id, $cancel_level); 
  900. return true; 
  901.  
  902. /** 
  903. * Function to list WordPress categories in hierarchical format. 
  904. * 
  905. * This is a helper function for the Membership Categories section in adminpages/membershiplevels.php 
  906. * 
  907. * @since 1.8.11 
  908. * 
  909. * @param int $parent_id 
  910. * @param array $level_categories 
  911. */ 
  912. function pmpro_listCategories($parent_id = 0, $level_categories = array()) { 
  913.  
  914. $args = array( 
  915. 'parent' => $parent_id,  
  916. 'hide_empty' => false,  
  917. ); 
  918.  
  919. $cats = get_categories(apply_filters('pmpro_list_categories_args', $args)); 
  920.  
  921. if($cats) { 
  922. foreach($cats as $cat) { 
  923. $name = 'membershipcategory_' . $cat->term_id; 
  924. if(!empty($level_categories)) 
  925. $checked = checked(in_array($cat->term_id, $level_categories), true, false); 
  926. else 
  927. $checked = ""; 
  928. echo "<ul><li class=membershipcategory><input type=checkbox name={$name} id={$name} value=yes {$checked}><label for={$name}>{$cat->name}</label>"; 
  929. pmpro_listCategories($cat->term_id, $level_categories); 
  930. echo '</li></ul>'; 
  931.  
  932. /** pmpro_toggleMembershipCategory() creates or deletes a linking entry between the membership level and post category tables. 
  933. * 
  934. * $level may either be the ID or name of the desired membership_level. 
  935. * $category must be a valid post category ID. 
  936. * 
  937. * Return values: 
  938. * Success returns boolean true. 
  939. * Failure returns a string containing the error message. 
  940. */ 
  941. function pmpro_toggleMembershipCategory( $level, $category, $value ) 
  942. global $wpdb; 
  943. $category = intval($category); 
  944.  
  945. if ( ($level = intval($level)) <= 0 ) 
  946. $safe = addslashes($level); 
  947. if ( ($level = intval($wpdb->get_var("SELECT id FROM {$wpdb->pmpro_membership_levels} WHERE name = '$safe' LIMIT 1"))) <= 0 ) 
  948. return __("Membership level not found.", 'paid-memberships-pro' ); 
  949.  
  950. if ( $value ) 
  951. $sql = "REPLACE INTO {$wpdb->pmpro_memberships_categories} (`membership_id`, `category_id`) VALUES ('$level', '$category')"; 
  952. $wpdb->query($sql); 
  953. if($wpdb->last_error) return $wpdb->last_error; 
  954. else 
  955. $sql = "DELETE FROM {$wpdb->pmpro_memberships_categories} WHERE `membership_id` = '$level' AND `category_id` = '$category' LIMIT 1"; 
  956. $wpdb->query($sql); 
  957. if($wpdb->last_error) return $wpdb->last_error; 
  958.  
  959. return true; 
  960.  
  961. /** pmpro_updateMembershipCategories() ensures that all those and only those categories given 
  962. * are associated with the given membership level. 
  963. * 
  964. * $level is a valid membership level ID or name 
  965. * $categories is an array of post category IDs 
  966. * 
  967. * Return values: 
  968. * Success returns boolean true. 
  969. * Failure returns a string containing the error message. 
  970. */ 
  971. function pmpro_updateMembershipCategories($level, $categories) 
  972. global $wpdb; 
  973.  
  974. if(!is_numeric($level)) 
  975. $level = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels WHERE name = '" . esc_sql($level) . "' LIMIT 1"); 
  976. if(empty($level)) 
  977. return __("Membership level not found.", 'paid-memberships-pro' ); 
  978.  
  979. // remove all existing links... 
  980. $sqlQuery = "DELETE FROM $wpdb->pmpro_memberships_categories WHERE `membership_id` = '" . esc_sql($level) . "'"; 
  981. $wpdb->query($sqlQuery); 
  982. if($wpdb->last_error) return $wpdb->last_error; 
  983.  
  984. // add the given links [back?] in... 
  985. foreach($categories as $cat) 
  986. if(is_string($r = pmpro_toggleMembershipCategory( $level, $cat, true))) 
  987. //uh oh, error 
  988. return $r; 
  989.  
  990. //all good 
  991. return true; 
  992.  
  993. /** pmpro_getMembershipCategories() returns the categories for a given level 
  994. * 
  995. * $level_id is a valid membership level ID 
  996. * 
  997. * Return values: 
  998. * Success returns boolean true. 
  999. * Failure returns boolean false. 
  1000. */ 
  1001. function pmpro_getMembershipCategories($level_id) 
  1002. $level_id = intval($level_id); 
  1003.  
  1004. global $wpdb; 
  1005. $categories = $wpdb->get_col("SELECT c.category_id 
  1006. FROM {$wpdb->pmpro_memberships_categories} AS c 
  1007. WHERE c.membership_id = '" . $level_id . "'"); 
  1008.  
  1009. return $categories; 
  1010.  
  1011.  
  1012. function pmpro_isAdmin($user_id = NULL) 
  1013. global $current_user, $wpdb; 
  1014. if(!$user_id) 
  1015. $user_id = $current_user->ID; 
  1016.  
  1017. if(!$user_id) 
  1018. return false; 
  1019.  
  1020. $admincap = user_can($user_id, "manage_options"); 
  1021. if($admincap) 
  1022. return true; 
  1023. else 
  1024. return false; 
  1025.  
  1026. function pmpro_replaceUserMeta($user_id, $meta_keys, $meta_values, $prev_values = NULL) 
  1027. //expects all arrays for last 3 params or all strings 
  1028. if(!is_array($meta_keys)) 
  1029. $meta_keys = array($meta_keys); 
  1030. $meta_values = array($meta_values); 
  1031. $prev_values = array($prev_values); 
  1032.  
  1033. for($i = 0; $i < count($meta_values); $i++) 
  1034. if($prev_values[$i]) 
  1035. update_user_meta($user_id, $meta_keys[$i], $meta_values[$i], $prev_values[$i]); 
  1036. else 
  1037. $old_value = get_user_meta($user_id, $meta_keys[$i], true); 
  1038. if($old_value) 
  1039. update_user_meta($user_id, $meta_keys[$i], $meta_values[$i], $old_value); 
  1040. else 
  1041. update_user_meta($user_id, $meta_keys[$i], $meta_values[$i]); 
  1042.  
  1043. return $i; 
  1044.  
  1045. function pmpro_getMetavalues($query) 
  1046. global $wpdb; 
  1047.  
  1048. $results = $wpdb->get_results($query); 
  1049. $r = new stdClass(); 
  1050. foreach($results as $result) 
  1051. if(!empty($r) && !empty($result->key)) 
  1052. $r->{$result->key} = $result->value; 
  1053.  
  1054. return $r; 
  1055.  
  1056. //function to return the pagination string 
  1057. function pmpro_getPaginationString($page = 1, $totalitems, $limit = 15, $adjacents = 1, $targetpage = "/", $pagestring = "&pn=") 
  1058. //defaults 
  1059. if(!$adjacents) $adjacents = 1; 
  1060. if(!$limit) $limit = 15; 
  1061. if(!$page) $page = 1; 
  1062. if(!$targetpage) $targetpage = "/"; 
  1063.  
  1064. //other vars 
  1065. $prev = $page - 1; //previous page is page - 1 
  1066. $next = $page + 1; //next page is page + 1 
  1067. $lastpage = ceil($totalitems / $limit); //lastpage is = total items / items per page, rounded up. 
  1068. $lpm1 = $lastpage - 1; //last page minus 1 
  1069.  
  1070. /** 
  1071. Now we apply our rules and draw the pagination object. 
  1072. We're actually saving the code to a variable in case we want to draw it more than once. 
  1073. */ 
  1074. $pagination = ""; 
  1075. if($lastpage > 1) 
  1076. $pagination .= "<div class=\"pmpro_pagination\""; 
  1077. if(!empty($margin) || !empty($padding)) 
  1078. $pagination .= " style=\""; 
  1079. if($margin) 
  1080. $pagination .= "margin: $margin;"; 
  1081. if($padding) 
  1082. $pagination .= "padding: $padding;"; 
  1083. $pagination .= "\""; 
  1084. $pagination .= ">"; 
  1085.  
  1086. //previous button 
  1087. if ($page > 1) 
  1088. $pagination .= "<a href=\"$targetpage$pagestring$prev\">« prev</a>"; 
  1089. else 
  1090. $pagination .= "<span class=\"disabled\">« prev</span>"; 
  1091.  
  1092. //pages 
  1093. if ($lastpage < 7 + ($adjacents * 2)) //not enough pages to bother breaking it up 
  1094. for ($counter = 1; $counter <= $lastpage; $counter++) 
  1095. if ($counter == $page) 
  1096. $pagination .= "<span class=\"current\">$counter</span>"; 
  1097. else 
  1098. $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>"; 
  1099. elseif($lastpage >= 7 + ($adjacents * 2)) //enough pages to hide some 
  1100. //close to beginning; only hide later pages 
  1101. if($page < 1 + ($adjacents * 3)) 
  1102. for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) 
  1103. if ($counter == $page) 
  1104. $pagination .= "<span class=\"current\">$counter</span>"; 
  1105. else 
  1106. $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>"; 
  1107. $pagination .= "..."; 
  1108. $pagination .= "<a href=\"" . $targetpage . $pagestring . $lpm1 . "\">$lpm1</a>"; 
  1109. $pagination .= "<a href=\"" . $targetpage . $pagestring . $lastpage . "\">$lastpage</a>"; 
  1110. //in middle; hide some front and some back 
  1111. elseif($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) 
  1112. $pagination .= "<a href=\"" . $targetpage . $pagestring . "1\">1</a>"; 
  1113. $pagination .= "<a href=\"" . $targetpage . $pagestring . "2\">2</a>"; 
  1114. $pagination .= "..."; 
  1115. for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) 
  1116. if ($counter == $page) 
  1117. $pagination .= "<span class=\"current\">$counter</span>"; 
  1118. else 
  1119. $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>"; 
  1120. $pagination .= "..."; 
  1121. $pagination .= "<a href=\"" . $targetpage . $pagestring . $lpm1 . "\">$lpm1</a>"; 
  1122. $pagination .= "<a href=\"" . $targetpage . $pagestring . $lastpage . "\">$lastpage</a>"; 
  1123. //close to end; only hide early pages 
  1124. else 
  1125. $pagination .= "<a href=\"" . $targetpage . $pagestring . "1\">1</a>"; 
  1126. $pagination .= "<a href=\"" . $targetpage . $pagestring . "2\">2</a>"; 
  1127. $pagination .= "..."; 
  1128. for ($counter = $lastpage - (1 + ($adjacents * 3)); $counter <= $lastpage; $counter++) 
  1129. if ($counter == $page) 
  1130. $pagination .= "<span class=\"current\">$counter</span>"; 
  1131. else 
  1132. $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>"; 
  1133.  
  1134. //next button 
  1135. if ($page < $counter - 1) 
  1136. $pagination .= "<a href=\"" . $targetpage . $pagestring . $next . "\">next »</a>"; 
  1137. else 
  1138. $pagination .= "<span class=\"disabled\">next »</span>"; 
  1139. $pagination .= "</div>\n"; 
  1140.  
  1141. return $pagination; 
  1142.  
  1143.  
  1144. function pmpro_calculateInitialPaymentRevenue($s = NULL, $l = NULL) 
  1145. global $wpdb; 
  1146.  
  1147. //if we're limiting users by search 
  1148. if($s || $l) 
  1149. $user_ids_query = "SELECT u.ID FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id WHERE mu.status = 'active' "; 
  1150. if($s) 
  1151. $user_ids_query .= "AND (u.user_login LIKE '%" . esc_sql($s) . "%' OR u.user_email LIKE '%" . esc_sql($s) . "%' OR um.meta_value LIKE '%$" . esc_sql(s) . "%') "; 
  1152. if($l) 
  1153. $user_ids_query .= "AND mu.membership_id = '" . esc_sql($l) . "' "; 
  1154.  
  1155. //query to sum initial payments 
  1156. $sqlQuery = "SELECT SUM(initial_payment) FROM $wpdb->pmpro_memberships_users WHERE `status` = 'active' "; 
  1157. if(!empty($user_ids_query)) 
  1158. $sqlQuery .= "AND user_id IN(" . $user_ids_query . ") "; 
  1159.  
  1160. $total = $wpdb->get_var($sqlQuery); 
  1161.  
  1162. return (double)$total; 
  1163.  
  1164. function pmpro_calculateRecurringRevenue($s, $l) 
  1165. global $wpdb; 
  1166.  
  1167. //if we're limiting users by search 
  1168. if($s || $l) 
  1169. $user_ids_query = "AND user_id IN(SELECT u.ID FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id WHERE mu.status = 'active' "; 
  1170. if($s) 
  1171. $user_ids_query .= "AND (u.user_login LIKE '%" . esc_sql($s) . "%' OR u.user_email LIKE '%" . esc_sql($s) . "%' OR um.meta_value LIKE '%" . esc_sql($s) . "%') "; 
  1172. if($l) 
  1173. $user_ids_query .= "AND mu.membership_id = '" . esc_sql($l) . "' "; 
  1174. $user_ids_query .= ")"; 
  1175. else 
  1176. $user_ids_query = ""; 
  1177.  
  1178. //4 queries to get annual earnings for each cycle period. currently ignoring trial periods and billing limits. 
  1179. $sqlQuery = " 
  1180. SELECT SUM((12/cycle_number)*billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Month' AND cycle_number <> 12 $user_ids_query 
  1181. UNION 
  1182. SELECT SUM((365/cycle_number)*billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Day' AND cycle_number <> 365 $user_ids_query 
  1183. UNION 
  1184. SELECT SUM((52/cycle_number)*billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Week' AND cycle_number <> 52 $user_ids_query 
  1185. UNION 
  1186. SELECT SUM(billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Year' $user_ids_query 
  1187. "; 
  1188.  
  1189. $annual_revenues = $wpdb->get_col($sqlQuery); 
  1190.  
  1191. $total = 0; 
  1192. foreach($annual_revenues as $r) 
  1193. $total += $r; 
  1194.  
  1195. return $total; 
  1196.  
  1197. function pmpro_generateUsername($firstname = "", $lastname = "", $email = "") 
  1198. global $wpdb; 
  1199.  
  1200. //try first initial + last name, firstname, lastname 
  1201. $firstname = preg_replace("/[^A-Za-z]/", "", $firstname); 
  1202. $lastname = preg_replace("/[^A-Za-z]/", "", $lastname); 
  1203. if($firstname && $lastname) 
  1204. $username = substr($firstname, 0, 1) . $lastname; 
  1205. elseif($firstname) 
  1206. $username = $firstname; 
  1207. elseif($lastname) 
  1208. $username = $lastname; 
  1209.  
  1210. //is it taken? 
  1211. $taken = $wpdb->get_var("SELECT user_login FROM $wpdb->users WHERE user_login = '" . esc_sql($username) . "' LIMIT 1"); 
  1212.  
  1213. if(!$taken) 
  1214. return $username; 
  1215.  
  1216. //try the beginning of the email address 
  1217. $emailparts = explode("@", $email); 
  1218. if(is_array($emailparts)) 
  1219. $email = preg_replace("/[^A-Za-z]/", "", $emailparts[0]); 
  1220.  
  1221. if(!empty($email)) 
  1222. $username = $email; 
  1223.  
  1224. //is this taken? if not, add numbers until it works 
  1225. $taken = true; 
  1226. $count = 0; 
  1227. while($taken) 
  1228. //add a # to the end 
  1229. if($count) 
  1230. $username = preg_replace("/[0-9]/", "", $username) . $count; 
  1231.  
  1232. //taken? 
  1233. $taken = $wpdb->get_var("SELECT user_login FROM $wpdb->users WHERE user_login = '" . esc_sql($username) . "' LIMIT 1"); 
  1234.  
  1235. //increment the number 
  1236. $count++; 
  1237.  
  1238. //must have a good username now 
  1239. return $username; 
  1240.  
  1241. //get a new random code for discount codes 
  1242. function pmpro_getDiscountCode($seed = NULL) 
  1243. global $wpdb; 
  1244.  
  1245. while(empty($code)) 
  1246. $scramble = md5(AUTH_KEY . current_time('timestamp') . $seed . SECURE_AUTH_KEY); 
  1247. $code = substr($scramble, 0, 10); 
  1248. $check = $wpdb->get_var("SELECT code FROM $wpdb->pmpro_discount_codes WHERE code = '" . esc_sql($code) . "' LIMIT 1"); 
  1249. if($check || is_numeric($code)) 
  1250. $code = NULL; 
  1251.  
  1252. return strtoupper($code); 
  1253.  
  1254. //is a discount code valid - level_id could be a scalar or an array (or unset) 
  1255. function pmpro_checkDiscountCode($code, $level_id = NULL, $return_errors = false) 
  1256. global $wpdb; 
  1257.  
  1258. $error = false; 
  1259. $dbcode = false; 
  1260.  
  1261. //no code, no code 
  1262. if(empty($code)) 
  1263. $error = __("No code was given to check.", 'paid-memberships-pro' ); 
  1264.  
  1265. //get code from db 
  1266. if(!$error) 
  1267. $dbcode = $wpdb->get_row("SELECT *, UNIX_TIMESTAMP(starts) as starts, UNIX_TIMESTAMP(expires) as expires FROM $wpdb->pmpro_discount_codes WHERE code ='" . esc_sql($code) . "' LIMIT 1"); 
  1268.  
  1269. //did we find it? 
  1270. if(empty($dbcode->id)) 
  1271. $error = __("The discount code could not be found.", 'paid-memberships-pro' ); 
  1272.  
  1273. //check if the code has started 
  1274. if(!$error) 
  1275. //fix the date timestamps 
  1276. $dbcode->starts = strtotime(date_i18n("m/d/Y", $dbcode->starts)); 
  1277. $dbcode->expires = strtotime(date_i18n("m/d/Y", $dbcode->expires)); 
  1278.  
  1279. //today 
  1280. $today = strtotime(date_i18n("m/d/Y 00:00:00", current_time("timestamp"))); 
  1281.  
  1282. //has this code started yet? 
  1283. if(!empty($dbcode->starts) && $dbcode->starts > $today) 
  1284. $error = sprintf(__("This discount code goes into effect on %s.", 'paid-memberships-pro' ), date_i18n(get_option('date_format'), $dbcode->starts)); 
  1285.  
  1286. //check if the code is expired 
  1287. if(!$error) 
  1288. if(!empty($dbcode->expires) && $dbcode->expires < $today) 
  1289. $error = sprintf(__("This discount code expired on %s.", 'paid-memberships-pro' ), date_i18n(get_option('date_format'), $dbcode->expires)); 
  1290.  
  1291. //have we run out of uses? 
  1292. if(!$error) 
  1293. if($dbcode->uses > 0) 
  1294. $used = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->pmpro_discount_codes_uses WHERE code_id = '" . $dbcode->id . "'"); 
  1295. if($used >= $dbcode->uses) 
  1296. $error = __("This discount code is no longer valid.", 'paid-memberships-pro' ); 
  1297.  
  1298. //if a level was passed check if this code applies 
  1299. if(!$error) 
  1300. $pmpro_check_discount_code_levels = apply_filters("pmpro_check_discount_code_levels", true, $dbcode->id); 
  1301. if(!empty($level_id) && $pmpro_check_discount_code_levels) 
  1302. // clean up level id for security before the database call 
  1303. if(is_array($level_id)) { 
  1304. $levelnums = array_map('intval', $level_id); 
  1305. $level_id = implode(', ', $levelnums); 
  1306. } else { 
  1307. $level_id = intval($level_id); 
  1308. $code_level = $wpdb->get_row("SELECT l.id, cl.*, l.name, l.description, l.allow_signups FROM $wpdb->pmpro_discount_codes_levels cl LEFT JOIN $wpdb->pmpro_membership_levels l ON cl.level_id = l.id WHERE cl.code_id = '" . $dbcode->id . "' AND cl.level_id IN (" . $level_id . ") LIMIT 1"); 
  1309.  
  1310. if(empty($code_level)) 
  1311. $error = __("This discount code does not apply to this membership level.", 'paid-memberships-pro' ); 
  1312.  
  1313. /** 
  1314. * Filter the results of the discount code check.  
  1315. * @since 1.7.13.1 
  1316. * 
  1317. * @param bool $okay true if code check is okay or false if there was an error 
  1318. * @param object $dbcode Object containing code data from the database row 
  1319. * @param int $level_id ID of the level the user is checking out for. 
  1320. * @param string $code Discount code string. 
  1321. *  
  1322. * @return mixed $okay true if okay, false or error message string if not okay 
  1323. */ 
  1324. $okay = !$error; 
  1325. $pmpro_check_discount_code = apply_filters("pmpro_check_discount_code", $okay, $dbcode, $level_id, $code); 
  1326. if(is_string($pmpro_check_discount_code)) 
  1327. $error = $pmpro_check_discount_code; //string returned, this is an error 
  1328. elseif(!$pmpro_check_discount_code && !$error) 
  1329. $error = true; //no error before, but filter returned error 
  1330. elseif($pmpro_check_discount_code) 
  1331. $error = false; //filter is true, so error false 
  1332.  
  1333. //return 
  1334. if($error) 
  1335. //there was an error 
  1336. if(!empty($return_errors)) 
  1337. return array(false, $error); 
  1338. else 
  1339. return false; 
  1340. else 
  1341. //guess we're all good 
  1342. if(!empty($return_errors)) 
  1343. return array(true, __("This discount code is okay.", 'paid-memberships-pro' )); 
  1344. else 
  1345. return true; 
  1346.  
  1347. function pmpro_no_quotes($s, $quotes = array("'", '"')) 
  1348. return str_replace($quotes, "", $s); 
  1349.  
  1350. //from: http://www.php.net/manual/en/function.implode.php#86845 
  1351. function pmpro_implodeToEnglish($array, $conjunction = 'and') 
  1352. // sanity check 
  1353. if (!$array || !count ($array)) 
  1354. return ''; 
  1355.  
  1356. // get last element 
  1357. $last = array_pop ($array); 
  1358.  
  1359. // if it was the only element - return it 
  1360. if (!count ($array)) 
  1361. return $last; 
  1362.  
  1363. //possibly translate the conjunction 
  1364. if($conjunction == 'and') 
  1365. $conjunction = __('and', 'paid-memberships-pro' ); 
  1366.  
  1367. return implode (', ', $array).' ' . $conjunction . ' '.$last; 
  1368.  
  1369. //from yoast wordpress seo 
  1370. function pmpro_text_limit( $text, $limit, $finish = '…') 
  1371. if( strlen( $text ) > $limit ) { 
  1372. $text = substr( $text, 0, $limit ); 
  1373. $text = substr( $text, 0, - ( strlen( strrchr( $text, ' ') ) ) ); 
  1374. $text .= $finish; 
  1375. return $text; 
  1376.  
  1377. /** pmpro_getMembershipLevelForUser() returns the first active membership level for a user 
  1378. * 
  1379. * If $user_id is omitted, the value will be retrieved from $current_user. 
  1380. * 
  1381. * Return values: 
  1382. * Success returns the level object. 
  1383. * Failure returns false. 
  1384. */ 
  1385. function pmpro_getMembershipLevelForUser($user_id = NULL, $force = false) 
  1386. if(empty($user_id)) 
  1387. global $current_user; 
  1388. $user_id = $current_user->ID; 
  1389.  
  1390. if(empty($user_id)) 
  1391. return false; 
  1392.  
  1393. //make sure user id is int for security 
  1394. $user_id = intval($user_id); 
  1395.  
  1396. global $all_membership_levels; 
  1397.  
  1398. if(isset($all_membership_levels[$user_id]) && !$force) 
  1399. return $all_membership_levels[$user_id]; 
  1400. else 
  1401. global $wpdb; 
  1402. $all_membership_levels[$user_id] = $wpdb->get_row("SELECT 
  1403. l.id AS ID,  
  1404. l.id as id,  
  1405. mu.id as subscription_id,  
  1406. l.name AS name,  
  1407. l.description,  
  1408. l.expiration_number,  
  1409. l.expiration_period,  
  1410. l.allow_signups,  
  1411. mu.initial_payment,  
  1412. mu.billing_amount,  
  1413. mu.cycle_number,  
  1414. mu.cycle_period,  
  1415. mu.billing_limit,  
  1416. mu.trial_amount,  
  1417. mu.trial_limit,  
  1418. mu.code_id as code_id,  
  1419. UNIX_TIMESTAMP(startdate) as startdate,  
  1420. UNIX_TIMESTAMP(enddate) as enddate 
  1421. FROM {$wpdb->pmpro_membership_levels} AS l 
  1422. JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id) 
  1423. WHERE mu.user_id = $user_id AND mu.status = 'active' 
  1424. LIMIT 1"); 
  1425.  
  1426. /** 
  1427. * pmpro_get_membership_level_for_user filter. 
  1428. * 
  1429. * Filters the returned level. 
  1430. * 
  1431. * @since 1.8.5.4 
  1432. * 
  1433. * @param object $level Level object. 
  1434. */ 
  1435. $all_membership_levels[$user_id] = apply_filters('pmpro_get_membership_level_for_user', $all_membership_levels[$user_id], $user_id); 
  1436.  
  1437. return $all_membership_levels[$user_id]; 
  1438.  
  1439. /** pmpro_getMembershipLevelsForUser() returns the membership levels for a user 
  1440. * 
  1441. * If $user_id is omitted, the value will be retrieved from $current_user. 
  1442. * By default it only includes actvie memberships. 
  1443. * 
  1444. * Return values: 
  1445. * Success returns an array of level objects. 
  1446. * Failure returns false. 
  1447. */ 
  1448. function pmpro_getMembershipLevelsForUser($user_id = NULL, $include_inactive = false) 
  1449. if(empty($user_id)) 
  1450. global $current_user; 
  1451. $user_id = $current_user->ID; 
  1452.  
  1453. if(empty($user_id)) 
  1454. return false; 
  1455.  
  1456. //make sure user id is int for security 
  1457. $user_id = intval($user_id); 
  1458.  
  1459. global $wpdb; 
  1460.  
  1461. $levels = $wpdb->get_results("SELECT 
  1462. l.id AS ID,  
  1463. l.id as id,  
  1464. mu.id as subscription_id,  
  1465. l.name,  
  1466. l.description,  
  1467. l.expiration_number,  
  1468. l.expiration_period,  
  1469. mu.initial_payment,  
  1470. mu.billing_amount,  
  1471. mu.cycle_number,  
  1472. mu.cycle_period,  
  1473. mu.billing_limit,  
  1474. mu.trial_amount,  
  1475. mu.trial_limit,  
  1476. mu.code_id as code_id,  
  1477. UNIX_TIMESTAMP(startdate) as startdate,  
  1478. UNIX_TIMESTAMP(enddate) as enddate 
  1479. FROM {$wpdb->pmpro_membership_levels} AS l 
  1480. JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id) 
  1481. WHERE mu.user_id = $user_id".($include_inactive?"":" AND mu.status = 'active'")); 
  1482. /** 
  1483. * pmpro_get_membership_levels_for_user filter. 
  1484. * 
  1485. * Filters the returned levels. 
  1486. * 
  1487. * @since 1.8.5.4 
  1488. * 
  1489. * @param array $levels Array of level objects. 
  1490. */ 
  1491. $levels = apply_filters('pmpro_get_membership_levels_for_user', $levels, $user_id); 
  1492.  
  1493. return $levels; 
  1494.  
  1495. /** pmpro_getLevel() returns the level object for a level 
  1496. * 
  1497. * $level may be the level id or name 
  1498. * 
  1499. * Return values: 
  1500. * Success returns the level object. 
  1501. * Failure returns false. 
  1502. */ 
  1503. function pmpro_getLevel($level) 
  1504. global $pmpro_levels; 
  1505.  
  1506. if(is_object($level) && !empty($level->id)) 
  1507. $level = $level->id; 
  1508.  
  1509. //was a name passed? (Todo: make sure level names have at least one non-numeric character. 
  1510. if(is_numeric($level)) 
  1511. $level_id = intval($level); 
  1512. if(isset($pmpro_levels[$level_id])) 
  1513. return $pmpro_levels[$level_id]; 
  1514. else 
  1515. global $wpdb; 
  1516. $pmpro_levels[$level_id] = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . $level_id . "' LIMIT 1"); 
  1517. return $pmpro_levels[$level_id]; 
  1518. else 
  1519. global $wpdb; 
  1520. $level_obj = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE name = '" . esc_sql($level) . "' LIMIT 1"); 
  1521.  
  1522. if(!empty($level_obj)) 
  1523. $level_id = $level_obj->id; 
  1524. else 
  1525. return false; 
  1526.  
  1527. $pmpro_levels[$level_id] = $level_obj; 
  1528. return $pmpro_levels[$level_id]; 
  1529.  
  1530. /** 
  1531. Function to populate pmpro_levels with all levels. We query the DB every time just to be sure we have the latest. 
  1532. This should be called if you want to be sure you get all levels as $pmpro_levels may only have a subset of levels. 
  1533. */ 
  1534. function pmpro_getAllLevels($include_hidden = false, $force = false) 
  1535. global $pmpro_levels, $wpdb; 
  1536.  
  1537. //just use what's cached (doesn't take into account include_hidden setting) 
  1538. if(!empty($pmpro_levels) && !$force) 
  1539. return $pmpro_levels; 
  1540.  
  1541. //build query 
  1542. $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels "; 
  1543. if(!$include_hidden) 
  1544. $sqlQuery .= " WHERE allow_signups = 1 ORDER BY id"; 
  1545.  
  1546. //get levels from the DB 
  1547. $raw_levels = $wpdb->get_results($sqlQuery); 
  1548.  
  1549. //lets put them into an array where the key is the id of the level 
  1550. $pmpro_levels = array(); 
  1551. foreach($raw_levels as $raw_level) 
  1552. $pmpro_levels[$raw_level->id] = $raw_level; 
  1553.  
  1554. return $pmpro_levels; 
  1555.  
  1556. /** 
  1557. * Get level at checkout and place into $pmpro_level global. 
  1558. */ 
  1559. function pmpro_getLevelAtCheckout($level_id = NULL, $discount_code = NULL) { 
  1560. global $pmpro_level, $wpdb, $post; 
  1561.  
  1562. //reset pmpro_level 
  1563. $pmpro_level = NULL; 
  1564.  
  1565. //default to level passed in via URL 
  1566. if(empty($level_id) && !empty($_REQUEST['level'])) { 
  1567. $level_id = intval($_REQUEST['level']); 
  1568.  
  1569. //default to discount code passed in 
  1570. if(empty($discount_code) && !empty($_REQUEST['discount_code'])) { 
  1571. $discount_code = preg_replace( "/[^A-Za-z0-9\-]/", "", $_REQUEST['discount_code'] ); 
  1572.  
  1573. //what level are they purchasing? (discount code passed) 
  1574. if (!empty($level_id) && !empty($discount_code)) {  
  1575. $discount_code_id = $wpdb->get_var( "SELECT id FROM $wpdb->pmpro_discount_codes WHERE code = '" . $discount_code . "' LIMIT 1" ); 
  1576.  
  1577. //check code 
  1578. $code_check = pmpro_checkDiscountCode( $discount_code, $level_id, true ); 
  1579. if ( $code_check[0] != false ) {  
  1580. $sqlQuery = "SELECT l.id, cl.*, l.name, l.description, l.allow_signups FROM $wpdb->pmpro_discount_codes_levels cl LEFT JOIN $wpdb->pmpro_membership_levels l ON cl.level_id = l.id LEFT JOIN $wpdb->pmpro_discount_codes dc ON dc.id = cl.code_id WHERE dc.code = '" . $discount_code . "' AND cl.level_id = '" . $level_id . "' LIMIT 1"; 
  1581. $pmpro_level = $wpdb->get_row( $sqlQuery ); 
  1582.  
  1583. //if the discount code doesn't adjust the level, let's just get the straight level 
  1584. if ( empty( $pmpro_level ) ) { 
  1585. $pmpro_level = $wpdb->get_row( "SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . $level_id . "' LIMIT 1" ); 
  1586.  
  1587. //filter adjustments to the level 
  1588. $pmpro_level->code_id = $discount_code_id; 
  1589. $pmpro_level = apply_filters( "pmpro_discount_code_level", $pmpro_level, $discount_code_id ); 
  1590. } else { 
  1591. //error with discount code, we want to halt checkout 
  1592. pmpro_setMessage($code_check[1], 'pmpro_error'); 
  1593.  
  1594. //what level are they purchasing? (no discount code) 
  1595. if ( empty( $pmpro_level ) && ! empty( $level_id ) ) { 
  1596. $pmpro_level = $wpdb->get_row( "SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql( $level_id ) . "' AND allow_signups = 1 LIMIT 1" ); 
  1597. } elseif ( empty( $pmpro_level ) && !empty( $post ) ) { 
  1598. //check if a level is defined in custom fields 
  1599. $default_level = get_post_meta( $post->ID, "pmpro_default_level", true ); 
  1600. if ( ! empty( $default_level ) ) { 
  1601. $pmpro_level = $wpdb->get_row( "SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql( $default_level ) . "' AND allow_signups = 1 LIMIT 1" ); 
  1602.  
  1603. //filter the level (for upgrades, etc) 
  1604. $pmpro_level = apply_filters( "pmpro_checkout_level", $pmpro_level ); 
  1605.  
  1606. return $pmpro_level; 
  1607.  
  1608. function pmpro_getCheckoutButton($level_id, $button_text = NULL, $classes = NULL) 
  1609. if(empty($button_text)) 
  1610. $button_text = __("Sign Up for !!name!! Now", 'paid-memberships-pro' ); 
  1611.  
  1612. if(empty($classes)) 
  1613. $classes = "pmpro_btn"; 
  1614.  
  1615. if(empty($level_id)) 
  1616. $r = __("Please specify a level id.", 'paid-memberships-pro' ); 
  1617. else 
  1618. //get level 
  1619. $level = pmpro_getLevel($level_id); 
  1620.  
  1621. //replace vars 
  1622. $replacements = array( 
  1623. "!!id!!" => $level->id,  
  1624. "!!name!!" => $level->name,  
  1625. "!!description!!" => $level->description,  
  1626. "!!confirmation!!" => $level->confirmation,  
  1627. "!!initial_payment!!" => $level->initial_payment,  
  1628. "!!billing_amount!!" => $level->billing_amount,  
  1629. "!!cycle_number!!" => $level->cycle_number,  
  1630. "!!cycle_period!!" => $level->cycle_period,  
  1631. "!!billing_limit!!" => $level->billing_limit,  
  1632. "!!trial_amount!!" => $level->trial_amount,  
  1633. "!!trial_limit!!" => $level->trial_limit,  
  1634. "!!expiration_number!!" => $level->expiration_number,  
  1635. "!!expiration_period!!" => $level->expiration_period 
  1636. ); 
  1637. $button_text = str_replace(array_keys($replacements), $replacements, $button_text); 
  1638.  
  1639. //button text 
  1640. $r = "<a href=\"" . pmpro_url("checkout", "?level=" . $level_id) . "\" class=\"" . $classes . "\">" . $button_text . "</a>"; 
  1641. return $r; 
  1642.  
  1643. /** 
  1644. * Get the "domain" from a URL. By domain, we mean the host name, minus any subdomains. So just the domain and TLD. 
  1645. * 
  1646. * @param string $url The URL to parse. (generally pass site_url() in WP) 
  1647. * @return string The domain. 
  1648. */ 
  1649. function pmpro_getDomainFromURL($url = NULL) 
  1650. $domainparts = parse_url($url); 
  1651. $domainparts = explode(".", $domainparts['host']); 
  1652. if(count($domainparts) > 1) 
  1653. //check for ips 
  1654. $isip = true; 
  1655. foreach($domainparts as $part) 
  1656. if(!is_numeric($part)) 
  1657. $isip = false; 
  1658. break; 
  1659.  
  1660. if($isip) 
  1661. //ip, e.g. 127.1.1.1 
  1662. $domain = implode(".", $domainparts); 
  1663. else 
  1664. //www.something.com, etc. 
  1665. $domain = $domainparts[count($domainparts)-2] . "." . $domainparts[count($domainparts)-1]; 
  1666. else 
  1667. //localhost or another single word domain 
  1668. $domain = $domainparts[0]; 
  1669.  
  1670. return $domain; 
  1671.  
  1672. /** 
  1673. Get a member's start date... either in general or for a specific level_id. 
  1674. */ 
  1675. if(!function_exists("pmpro_getMemberStartdate")) 
  1676. function pmpro_getMemberStartdate($user_id = NULL, $level_id = 0) 
  1677. if(empty($user_id)) 
  1678. global $current_user; 
  1679. $user_id = $current_user->ID; 
  1680.  
  1681. //make sure user and level id are int for security 
  1682. $user_id = intval($user_id); 
  1683. $level_id = intval($level_id); 
  1684.  
  1685. global $pmpro_startdates; //for cache 
  1686. if(empty($pmpro_startdates[$user_id][$level_id])) 
  1687. global $wpdb; 
  1688.  
  1689. if(!empty($level_id)) 
  1690. $sqlQuery = "SELECT UNIX_TIMESTAMP(startdate) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND membership_id IN(" . esc_sql($level_id) . ") AND user_id = '" . $user_id . "' ORDER BY id LIMIT 1"; 
  1691. else 
  1692. $sqlQuery = "SELECT UNIX_TIMESTAMP(startdate) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND user_id = '" . $user_id . "' ORDER BY id LIMIT 1"; 
  1693.  
  1694. $startdate = apply_filters("pmpro_member_startdate", $wpdb->get_var($sqlQuery), $user_id, $level_id); 
  1695.  
  1696. $pmpro_startdates[$user_id][$level_id] = $startdate; 
  1697.  
  1698. return $pmpro_startdates[$user_id][$level_id]; 
  1699.  
  1700. /** 
  1701. How long has this member been a member 
  1702. */ 
  1703. if(!function_exists("pmpro_getMemberDays")) 
  1704. function pmpro_getMemberDays($user_id = NULL, $level_id = 0) 
  1705. if(empty($user_id)) 
  1706. global $current_user; 
  1707. $user_id = $current_user->ID; 
  1708.  
  1709. global $pmpro_member_days; 
  1710. if(empty($pmpro_member_days[$user_id][$level_id])) 
  1711. $startdate = pmpro_getMemberStartdate($user_id, $level_id); 
  1712.  
  1713. //check that there was a startdate at all 
  1714. if(empty($startdate)) 
  1715. $pmpro_member_days[$user_id][$level_id] = 0; 
  1716. else 
  1717. $now = current_time('timestamp'); 
  1718. $days = ($now - $startdate)/3600/24; 
  1719.  
  1720. $pmpro_member_days[$user_id][$level_id] = $days; 
  1721.  
  1722. return $pmpro_member_days[$user_id][$level_id]; 
  1723.  
  1724. //the start of a message handling script 
  1725. function pmpro_setMessage($message, $type, $force = false) 
  1726. global $pmpro_msg, $pmpro_msgt; 
  1727.  
  1728. //for now, we only show the first message generated 
  1729. if($force || empty($pmpro_msg)) 
  1730. $pmpro_msg = apply_filters('pmpro_set_message', $message, $type); 
  1731. $pmpro_msgt = $type; 
  1732.  
  1733. /** 
  1734. * Show a a PMPro message set via pmpro_setMessage 
  1735. * 
  1736. * @since 1.8.5 
  1737. */ 
  1738. function pmpro_showMessage() 
  1739. global $pmpro_msg, $pmpro_msgt; 
  1740.  
  1741. if(!empty($pmpro_msg)) 
  1742. ?> 
  1743. <div class="<?php echo $pmpro_msgt;?>"> 
  1744. <p><?php echo $pmpro_msg;?></p> 
  1745. </div> 
  1746. <?php 
  1747.  
  1748. //used in class definitions for input fields to see if there was an error 
  1749. function pmpro_getClassForField($field) 
  1750. global $pmpro_error_fields, $pmpro_required_billing_fields, $pmpro_required_user_fields; 
  1751. $classes = array(); 
  1752.  
  1753. //error on this field? 
  1754. if(!empty($pmpro_error_fields) && in_array($field, $pmpro_error_fields)) 
  1755. $classes[] = "pmpro_error"; 
  1756.  
  1757. if(is_array($pmpro_required_billing_fields) && is_array($pmpro_required_user_fields)) 
  1758. $required_fields = array_merge(array_keys($pmpro_required_billing_fields), array_keys($pmpro_required_user_fields)); 
  1759. elseif(is_array($pmpro_required_billing_fields)) 
  1760. $required_fields = array_keys($pmpro_required_billing_fields); 
  1761. elseif(is_array($pmpro_required_user_fields)) 
  1762. $required_fields = array_keys($pmpro_required_user_fields); 
  1763. else 
  1764. $required_fields = array(); 
  1765.  
  1766. //required? 
  1767. if(in_array($field, $required_fields)) 
  1768. $classes[] = "pmpro_required"; 
  1769.  
  1770. $classes = apply_filters("pmpro_field_classes", $classes, $field); 
  1771.  
  1772. if(!empty($classes)) 
  1773. return implode(" ", $classes); 
  1774. else 
  1775. return ""; 
  1776.  
  1777. //get a var from $_GET or $_POST 
  1778. function pmpro_getParam($index, $method = "REQUEST", $default = "") 
  1779. if($method == "REQUEST") 
  1780. if(!empty($_REQUEST[$index])) 
  1781. return $_REQUEST[$index]; 
  1782. elseif($method == "POST") 
  1783. if(!empty($_POST[$index])) 
  1784. return $_POST[$index]; 
  1785. elseif($method == "GET") 
  1786. if(!empty($_GET[$index])) 
  1787. return $_GET[$index]; 
  1788.  
  1789. return $default; 
  1790.  
  1791. /** 
  1792. Format an address from address, city, state, zip, country, and phone 
  1793. */ 
  1794. function pmpro_formatAddress($name, $address1, $address2, $city, $state, $zip, $country, $phone, $nl2br = true) 
  1795. $address = ""; 
  1796.  
  1797. if(!empty($name)) 
  1798. $address .= $name . "\n"; 
  1799.  
  1800. if(!empty($address1)) 
  1801. $address .= $address1 . "\n"; 
  1802.  
  1803. if(!empty($address2)) 
  1804. $address .= $address2 . "\n"; 
  1805.  
  1806. if(!empty($city) && !empty($state)) 
  1807. $address .= $city . ", " . $state; 
  1808.  
  1809. if(!empty($zip)) 
  1810. $address .= " " . $zip; 
  1811.  
  1812. $address .= "\n"; 
  1813.  
  1814. if(!empty($country)) 
  1815. $address .= $country . "\n"; 
  1816.  
  1817. if(!empty($phone)) 
  1818. $address .= formatPhone($phone); 
  1819.  
  1820. if($nl2br) 
  1821. $address = nl2br($address); 
  1822.  
  1823. return apply_filters('pmpro_formatted_address', $address, $name, $address1, $address2, $city, $state, $zip, $country, $phone, $nl2br ); 
  1824.  
  1825. /** 
  1826. Checks if all required settings are set. 
  1827. */ 
  1828. function pmpro_is_ready() 
  1829. global $wpdb, $pmpro_pages, $pmpro_level_ready, $pmpro_gateway_ready, $pmpro_pages_ready; 
  1830.  
  1831. //check if there is at least one level 
  1832. $pmpro_level_ready = (bool)$wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels LIMIT 1"); 
  1833.  
  1834. //check if the gateway settings are good. first check if it's needed (is there paid membership level) 
  1835. $paid_membership_level = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels WHERE allow_signups = 1 AND (initial_payment > 0 OR billing_amount > 0 OR trial_amount > 0) LIMIT 1"); 
  1836. $paid_user_subscription = $wpdb->get_var("SELECT user_id FROM $wpdb->pmpro_memberships_users WHERE initial_payment > 0 OR billing_amount > 0 OR trial_amount > 0 LIMIT 1"); 
  1837.  
  1838. if(empty($paid_membership_level) && empty($paid_user_subscription)) 
  1839. //no paid membership level now or attached to a user. we don't need the gateway setup 
  1840. $pmpro_gateway_ready = true; 
  1841. else 
  1842. $gateway = pmpro_getOption("gateway"); 
  1843. if($gateway == "authorizenet") 
  1844. if(pmpro_getOption("gateway_environment") && pmpro_getOption("loginname") && pmpro_getOption("transactionkey")) 
  1845. $pmpro_gateway_ready = true; 
  1846. else 
  1847. $pmpro_gateway_ready = false; 
  1848. elseif($gateway == "paypal" || $gateway == "paypalexpress") 
  1849. if(pmpro_getOption("gateway_environment") && pmpro_getOption("gateway_email") && pmpro_getOption("apiusername") && pmpro_getOption("apipassword") && pmpro_getOption("apisignature")) 
  1850. $pmpro_gateway_ready = true; 
  1851. else 
  1852. $pmpro_gateway_ready = false; 
  1853. elseif($gateway == "paypalstandard") 
  1854. if(pmpro_getOption("gateway_environment") && pmpro_getOption("gateway_email")) 
  1855. $pmpro_gateway_ready = true; 
  1856. else 
  1857. $pmpro_gateway_ready = false; 
  1858. elseif($gateway == "payflowpro") 
  1859. if(pmpro_getOption("payflow_partner") && pmpro_getOption("payflow_vendor") && pmpro_getOption("payflow_user") && pmpro_getOption("payflow_pwd")) 
  1860. $pmpro_gateway_ready = true; 
  1861. else 
  1862. $pmpro_gateway_ready = false; 
  1863. elseif($gateway == "stripe") 
  1864. if(pmpro_getOption("gateway_environment") && pmpro_getOption("stripe_secretkey") && pmpro_getOption("stripe_publishablekey")) 
  1865. $pmpro_gateway_ready = true; 
  1866. else 
  1867. $pmpro_gateway_ready = false; 
  1868. elseif($gateway == "braintree") 
  1869. if(pmpro_getOption("gateway_environment") && pmpro_getOption("braintree_merchantid") && pmpro_getOption("braintree_publickey") && pmpro_getOption("braintree_privatekey")) 
  1870. $pmpro_gateway_ready = true; 
  1871. else 
  1872. $pmpro_gateway_ready = false; 
  1873. elseif($gateway == "twocheckout") 
  1874. if(pmpro_getOption("gateway_environment") && pmpro_getOption("twocheckout_apiusername") && pmpro_getOption("twocheckout_apipassword")) 
  1875. $pmpro_gateway_ready = true; 
  1876. else 
  1877. $pmpro_gateway_ready = false; 
  1878. elseif($gateway == "cybersource") 
  1879. if(pmpro_getOption("gateway_environment") && pmpro_getOption("cybersource_merchantid") && pmpro_getOption("cybersource_securitykey")) 
  1880. $pmpro_gateway_ready = true; 
  1881. else 
  1882. $pmpro_gateway_ready = false; 
  1883. elseif($gateway == "check") 
  1884. $pmpro_gateway_ready = true; 
  1885. else 
  1886. $pmpro_gateway_ready = false; 
  1887.  
  1888. //check if we have all pages 
  1889. if($pmpro_pages["account"] && 
  1890. $pmpro_pages["billing"] && 
  1891. $pmpro_pages["cancel"] && 
  1892. $pmpro_pages["checkout"] && 
  1893. $pmpro_pages["confirmation"] && 
  1894. $pmpro_pages["invoice"] && 
  1895. $pmpro_pages["levels"]) 
  1896. $pmpro_pages_ready = true; 
  1897. else 
  1898. $pmpro_pages_ready = false; 
  1899.  
  1900. //now check both 
  1901. if($pmpro_gateway_ready && $pmpro_pages_ready) 
  1902. $r = true; 
  1903. else 
  1904. $r = false; 
  1905.  
  1906. /** 
  1907. * Filter to determine if PMPro setup is complete or 
  1908. * if notices or warnings need to be shown in the PMPro settings. 
  1909. * 
  1910. * Note: The filter should return true or false and also set 
  1911. * the $pmpro_level_ready, $pmpro_gateway_ready, $pmpro_pages_ready global variabls. 
  1912. * 
  1913. * @since 1.8.4.5 
  1914. * 
  1915. * @param bool $r ready? 
  1916. */ 
  1917. $r = apply_filters('pmpro_is_ready', $r); 
  1918.  
  1919. return $r; 
  1920.  
  1921. /** 
  1922. * Format a price per the currency settings. 
  1923. * 
  1924. * @since 1.7.15 
  1925. */ 
  1926. function pmpro_formatPrice($price) 
  1927. global $pmpro_currency, $pmpro_currency_symbol, $pmpro_currencies; 
  1928.  
  1929. //start with the price formatted with two decimals 
  1930. $formatted = number_format((double)$price, 2); 
  1931.  
  1932. //settings stored in array? 
  1933. if(!empty($pmpro_currencies[$pmpro_currency]) && is_array($pmpro_currencies[$pmpro_currency])) 
  1934. //format number do decimals, with decimal_separator and thousands_separator 
  1935. $formatted = number_format($price,  
  1936. (isset($pmpro_currencies[$pmpro_currency]['decimals']) ? (int)$pmpro_currencies[$pmpro_currency]['decimals'] : 2),  
  1937. (isset($pmpro_currencies[$pmpro_currency]['decimal_separator']) ? $pmpro_currencies[$pmpro_currency]['decimal_separator'] : '.'),  
  1938. (isset($pmpro_currencies[$pmpro_currency]['thousands_separator']) ? $pmpro_currencies[$pmpro_currency]['thousands_separator'] : ', ') 
  1939. ); 
  1940.  
  1941. //which side is the symbol on? 
  1942. if(!empty($pmpro_currencies[$pmpro_currency]['position']) && $pmpro_currencies[$pmpro_currency]['position']== 'left') 
  1943. $formatted = $pmpro_currency_symbol . $formatted; 
  1944. else 
  1945. $formatted = $formatted . $pmpro_currency_symbol; 
  1946. else 
  1947. $formatted = $pmpro_currency_symbol . $formatted; //default to symbol on the left 
  1948.  
  1949. //filter 
  1950. return apply_filters('pmpro_format_price', $formatted, $price, $pmpro_currency, $pmpro_currency_symbol); 
  1951.  
  1952. /** 
  1953. * Which side does the currency symbol go on? 
  1954. * 
  1955. * @since 1.7.15 
  1956. */ 
  1957. function pmpro_getCurrencyPosition() 
  1958. global $pmpro_currency, $pmpro_currencies; 
  1959.  
  1960. if(!empty($pmpro_currencies[$pmpro_currency]) && is_array($pmpro_currencies[$pmpro_currency]) && !empty($pmpro_currencies[$pmpro_currency]['position'])) 
  1961. return $pmpro_currencies[$pmpro_currency]['position']; 
  1962. else 
  1963. return "left"; 
  1964.  
  1965. /** 
  1966. * What gateway should we be using? 
  1967. * 
  1968. * @since 1.8 
  1969. */ 
  1970. function pmpro_getGateway() 
  1971. //grab from param or options 
  1972. if (!empty($_REQUEST['gateway'])) 
  1973. $gateway = $_REQUEST['gateway']; //gateway passed as param 
  1974. elseif (!empty($_REQUEST['review'])) 
  1975. $gateway = "paypalexpress"; //if review param assume paypalexpress 
  1976. else 
  1977. $gateway = pmpro_getOption("gateway"); //get from options 
  1978.  
  1979. //set valid gateways - the active gateway in the settings and any gateway added through the filter will be allowed 
  1980. if(pmpro_getOption("gateway", true) == "paypal") 
  1981. $valid_gateways = apply_filters("pmpro_valid_gateways", array("paypal", "paypalexpress")); 
  1982. else 
  1983. $valid_gateways = apply_filters("pmpro_valid_gateways", array(pmpro_getOption("gateway", true))); 
  1984.  
  1985. //make sure it's valid 
  1986. if(!in_array($gateway, $valid_gateways)) 
  1987. $gateway = false; 
  1988.  
  1989. //filter for good measure 
  1990. $gateway = apply_filters('pmpro_get_gateway', $gateway, $valid_gateways); 
  1991.  
  1992. return $gateway; 
  1993.  
  1994. /** 
  1995. * Does the date provided fall in this month. 
  1996. * Used in logins/visits/views report. 
  1997. * 
  1998. * @since 1.8.3 
  1999. */ 
  2000. function pmpro_isDateThisMonth($str) 
  2001. $now = current_time('timestamp'); 
  2002. $this_month = intval(date_i18n("n", $now)); 
  2003. $this_year = intval(date_i18n("Y", $now)); 
  2004.  
  2005. $date = strtotime($str, $now); 
  2006. $date_month = intval(date_i18n("n", $date)); 
  2007. $date_year = intval(date_i18n("Y", $date)); 
  2008.  
  2009. if($date_month === $this_month && $date_year === $this_year) 
  2010. return true; 
  2011. else 
  2012. return false; 
  2013.  
  2014. /** 
  2015. * Function to generate PMPro front end pages. 
  2016. * 
  2017. * @param array $pages { 
  2018. * Formatted as array($name => $title) or array(array('title'=>'The Title', 'content'=>'The Content')) 
  2019. * 
  2020. * @type string $name Page name. (Letters, numbers, and underscores only.) 
  2021. * @type string $title Page title. 
  2022. * } 
  2023. * @return array $created_pages Created page IDs. 
  2024. * @since 1.8.5 
  2025. */ 
  2026. function pmpro_generatePages($pages) { 
  2027.  
  2028. global $pmpro_pages; 
  2029.  
  2030. $pages_created = array(); 
  2031.  
  2032. if(!empty($pages)) { 
  2033. foreach($pages as $name => $page) { 
  2034.  
  2035. //does it already exist? 
  2036. if(!empty($pmpro_pages[$name])) 
  2037. continue; 
  2038.  
  2039. //no id set. create an array to store the page info 
  2040. if(is_array($page)) { 
  2041. $title = $page['title']; 
  2042. $content = $page['content']; 
  2043. } else { 
  2044. $title = $page; 
  2045. $content = '[pmpro_' . $name . ']'; 
  2046.  
  2047. $insert = array( 
  2048. 'post_title' => $title,  
  2049. 'post_status' => 'publish',  
  2050. 'post_type' => 'page',  
  2051. 'post_content' => $content,  
  2052. 'comment_status' => 'closed',  
  2053. 'ping_status' => 'closed' 
  2054. ); 
  2055.  
  2056. //make non-account pages a subpage of account 
  2057. if ($name != "account") { 
  2058. $insert['post_parent'] = $pmpro_pages['account']; 
  2059.  
  2060. //create the page 
  2061. $pmpro_pages[$name] = wp_insert_post($insert); 
  2062.  
  2063. //update the option too 
  2064. pmpro_setOption($name . "_page_id", $pmpro_pages[$name]); 
  2065. $pages_created[] = $pmpro_pages[$name]; 
  2066.  
  2067. return $pages_created; 
  2068.  
  2069. /** 
  2070. * Schedule a periodic event unless one with the same hook is already scheduled. 
  2071. * 
  2072. * @param int $timestamp Timestamp for when to run the event. 
  2073. * @param string $recurrence How often the event should recur. 
  2074. * @param string $hook Action hook to execute when cron is run. 
  2075. * @param array $args Optional. Arguments to pass to the hook's callback function. 
  2076. * @return false|void False when an event is not scheduled. 
  2077. * @since 1.8.7.3 
  2078. */ 
  2079. function pmpro_maybe_schedule_event( $timestamp, $recurrence, $hook, $args = array()) { 
  2080. $next = wp_next_scheduled($hook, $args); 
  2081. if(empty($next)) 
  2082. return wp_schedule_event($timestamp, $recurrence, $hook, $args); 
  2083. else 
  2084. return false; 
  2085.  
  2086. /** 
  2087. * Get an array of orders for a specific checkout ID 
  2088. * 
  2089. * @param int $checkout_id Checkout ID 
  2090. * @since 1.8.11 
  2091. */ 
  2092. function pmpro_getMemberOrdersByCheckoutID($checkout_id) { 
  2093. global $wpdb; 
  2094.  
  2095. $order_ids = $wpdb->get_col($wpdb->prepare("SELECT id FROM $wpdb->pmpro_membership_orders WHERE checkout_id = %d", $checkout_id)); 
  2096.  
  2097. $r = array(); 
  2098. foreach($order_ids as $order_id) { 
  2099. $r[] = new MemberOrder($order_id); 
  2100.  
  2101. return $r; 
.