/app/model/class-ms-model-communication.php

  1. <?php 
  2. /** 
  3. * @copyright Incsub (http://incsub.com/) 
  4. * 
  5. * @license http://opensource.org/licenses/GPL-2.0 GNU General Public License, version 2 (GPL-2.0) 
  6. * 
  7. * This program is free software; you can redistribute it and/or modify 
  8. * it under the terms of the GNU General Public License, version 2, as 
  9. * published by the Free Software Foundation. 
  10. * 
  11. * This program is distributed in the hope that it will be useful,  
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
  14. * GNU General Public License for more details. 
  15. * 
  16. * You should have received a copy of the GNU General Public License 
  17. * along with this program; if not, write to the Free Software 
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  
  19. * MA 02110-1301 USA 
  20. * 
  21. */ 
  22.  
  23. /** 
  24. * Communication model. 
  25. * 
  26. * Persisted by parent class MS_Model_CustomPostType. 
  27. * 
  28. * @since 1.0.0 
  29. * 
  30. * @package Membership2 
  31. * @subpackage Model 
  32. */ 
  33. class MS_Model_Communication extends MS_Model_CustomPostType { 
  34.  
  35. /** 
  36. * Model custom post type. 
  37. * 
  38. * Both static and class property are used to handle php 5.2 limitations. 
  39. * 
  40. * @since 1.0.0 
  41. * @var string $POST_TYPE 
  42. */ 
  43. protected static $POST_TYPE = 'ms_communication'; 
  44.  
  45. /** 
  46. * Communication types, static reference to loaded child objects. 
  47. * 
  48. * @since 1.0.0 
  49. * @var array $communications 
  50. */ 
  51. protected static $communications = array(); 
  52.  
  53. /** 
  54. * Communication type constants. 
  55. * 
  56. * @since 1.0.0 
  57. * @see $type 
  58. * @var string The communication type 
  59. */ 
  60. const COMM_TYPE_REGISTRATION = 'type_registration'; 
  61. const COMM_TYPE_REGISTRATION_FREE = 'type_registration_free'; 
  62. const COMM_TYPE_RENEWED = 'renewed'; 
  63. const COMM_TYPE_INVOICE = 'type_invoice'; 
  64. const COMM_TYPE_BEFORE_FINISHES = 'type_before_finishes'; 
  65. const COMM_TYPE_FINISHED = 'type_finished'; 
  66. const COMM_TYPE_AFTER_FINISHES = 'type_after_finishes'; 
  67. const COMM_TYPE_CANCELLED = 'type_cancelled'; 
  68. const COMM_TYPE_BEFORE_TRIAL_FINISHES = 'type_before_trial_finishes'; 
  69. const COMM_TYPE_INFO_UPDATE = 'type_info_update'; 
  70. const COMM_TYPE_CREDIT_CARD_EXPIRE = 'type_credit_card_expire'; 
  71. const COMM_TYPE_FAILED_PAYMENT = 'type_failed_payment'; 
  72. const COMM_TYPE_BEFORE_PAYMENT_DUE = 'type_before_payment_due'; 
  73. const COMM_TYPE_AFTER_PAYMENT_DUE = 'type_after_payment_due'; 
  74.  
  75. /** 
  76. * Communication variable constants. 
  77. * 
  78. * These variables are used inside emails and are replaced by variable value. 
  79. * 
  80. * @since 1.0.0 
  81. * @see comm_vars 
  82. * @var string The communication variable name. 
  83. */ 
  84. const COMM_VAR_MS_NAME = '%ms-name%'; 
  85. const COMM_VAR_MS_INVOICE = '%ms-invoice%'; 
  86. const COMM_VAR_MS_ACCOUNT_PAGE_URL = '%ms-account-page-url%'; 
  87. const COMM_VAR_MS_REMAINING_DAYS = '%ms-remaining-days%'; 
  88. const COMM_VAR_MS_REMAINING_TRIAL_DAYS = '%ms-remaining-trial-days%'; 
  89. const COMM_VAR_MS_EXPIRY_DATE = '%ms-expiry-date%'; 
  90. const COMM_VAR_USER_DISPLAY_NAME = '%user-display-name%'; 
  91. const COMM_VAR_USER_FIRST_NAME = '%user-first-name%'; 
  92. const COMM_VAR_USER_LAST_NAME = '%user-last-name%'; 
  93. const COMM_VAR_USERNAME = '%username%'; 
  94. const COMM_VAR_BLOG_NAME = '%blog-name%'; 
  95. const COMM_VAR_BLOG_URL = '%blog-url%'; 
  96. const COMM_VAR_NET_NAME = '%network-name%'; 
  97. const COMM_VAR_NET_URL = '%network-url%'; 
  98.  
  99. /** 
  100. * Communication type. 
  101. * 
  102. * @since 1.0.0 
  103. * @var string The communication type. 
  104. */ 
  105. protected $type; 
  106.  
  107. /** 
  108. * Email subject. 
  109. * 
  110. * @since 1.0.0 
  111. * @var string The email subject. 
  112. */ 
  113. protected $subject; 
  114.  
  115. /** 
  116. * Email body message. 
  117. * 
  118. * @since 1.0.0 
  119. * @var string The email body message. 
  120. */ 
  121. protected $message; 
  122.  
  123. /** 
  124. * Communication period enabled. 
  125. * 
  126. * When the communication has a period to consider. 
  127. * 
  128. * @since 1.0.0 
  129. * @var bool The period enabled status. 
  130. */ 
  131. protected $period_enabled = false; 
  132.  
  133. /** 
  134. * The communication period settings. 
  135. * 
  136. * @since 1.0.0 
  137. * @var array 
  138. */ 
  139. protected $period = array( 
  140. 'period_unit' => 1,  
  141. 'period_type' => MS_Helper_Period::PERIOD_TYPE_DAYS,  
  142. ); 
  143.  
  144. /** 
  145. * Communication enabled status. 
  146. * 
  147. * @since 1.0.0 
  148. * @var string The communication enabled status. 
  149. */ 
  150. protected $enabled; 
  151.  
  152. /** 
  153. * Communication carbon copy enabled. 
  154. * 
  155. * @since 1.0.0 
  156. * @var string The communication carbon copy enabled status. 
  157. */ 
  158. protected $cc_enabled; 
  159.  
  160. /** 
  161. * Communication copied recipient email. 
  162. * 
  163. * @since 1.0.0 
  164. * @var string The copied recipient email. 
  165. */ 
  166. protected $cc_email; 
  167.  
  168. /** 
  169. * Communication variables. 
  170. * 
  171. * @since 1.0.0 
  172. * @var string The communication vars. 
  173. */ 
  174. protected $comm_vars = array(); 
  175.  
  176. /** 
  177. * Communication queue of emails to send. 
  178. * 
  179. * @since 1.0.0 
  180. * @var string The communication queue. 
  181. */ 
  182. protected $queue = array(); 
  183.  
  184. /** 
  185. * Communication sent emails queue. 
  186. * 
  187. * Keep for a limited history of sent emails. 
  188. * 
  189. * @since 1.0.0 
  190. * @var string The communication sent queue. 
  191. */ 
  192. protected $sent_queue = array(); 
  193.  
  194. /** 
  195. * Communication default content type. 
  196. * 
  197. * @since 1.0.0 
  198. * @var string The communication default content type. 
  199. */ 
  200. protected $content_type = 'text/html'; 
  201.  
  202. /** 
  203. * Don't persist this fields. 
  204. * 
  205. * @since 1.0.0 
  206. * @var string[] The fields to ignore when persisting. 
  207. */ 
  208. static public $ignore_fields = array( 
  209. 'message',  
  210. 'description',  
  211. 'name',  
  212. 'comm_vars',  
  213. ); 
  214.  
  215. /** 
  216. * Returns the post-type of the current object. 
  217. * 
  218. * @since 2.0.0 
  219. * @return string The post-type name. 
  220. */ 
  221. public static function get_post_type() { 
  222. return parent::_post_type( self::$POST_TYPE ); 
  223.  
  224. /** 
  225. * Get custom register post type args for this model. 
  226. * 
  227. * @since 1.0.0 
  228. */ 
  229. public static function get_register_post_type_args() { 
  230. $args = array( 
  231. 'label' => __( 'Membership2 Email Templates', MS_TEXT_DOMAIN ),  
  232. ); 
  233.  
  234. return apply_filters( 
  235. 'ms_customposttype_register_args',  
  236. $args,  
  237. self::get_post_type() 
  238. ); 
  239.  
  240. /** 
  241. * Communication constructor. 
  242. * 
  243. * @since 1.0.0 
  244. */ 
  245. public function __construct() { 
  246. $this->comm_vars = array( 
  247. self::COMM_VAR_MS_NAME => __( 'Subscription: Membership Name', MS_TEXT_DOMAIN ),  
  248. self::COMM_VAR_MS_REMAINING_DAYS => __( 'Subscription: Remaining days', MS_TEXT_DOMAIN ),  
  249. self::COMM_VAR_MS_REMAINING_TRIAL_DAYS => __( 'Subscription: Remaining trial days', MS_TEXT_DOMAIN ),  
  250. self::COMM_VAR_MS_EXPIRY_DATE => __( 'Subscription: Expiration date', MS_TEXT_DOMAIN ),  
  251. self::COMM_VAR_MS_INVOICE => __( 'Subscription: Current Invoice', MS_TEXT_DOMAIN ),  
  252. self::COMM_VAR_USER_DISPLAY_NAME => __( 'User: Display name', MS_TEXT_DOMAIN ),  
  253. self::COMM_VAR_USER_FIRST_NAME => __( 'User: First name', MS_TEXT_DOMAIN ),  
  254. self::COMM_VAR_USER_LAST_NAME => __( 'User: Last name', MS_TEXT_DOMAIN ),  
  255. self::COMM_VAR_USERNAME => __( 'User: Login name', MS_TEXT_DOMAIN ),  
  256. self::COMM_VAR_MS_ACCOUNT_PAGE_URL => __( 'Site: User Account URL', MS_TEXT_DOMAIN ),  
  257. self::COMM_VAR_BLOG_NAME => __( 'Site: Name', MS_TEXT_DOMAIN ),  
  258. self::COMM_VAR_BLOG_URL => __( 'Site: URL', MS_TEXT_DOMAIN ),  
  259. ); 
  260.  
  261. if ( is_multisite() ) { 
  262. $this->comm_vars[self::COMM_VAR_NET_NAME] = __( 'Network: Name', MS_TEXT_DOMAIN ); 
  263. $this->comm_vars[self::COMM_VAR_NET_URL] = __( 'Network: URL', MS_TEXT_DOMAIN ); 
  264.  
  265. /** 
  266. * Set description field to persist in WP column. 
  267. * 
  268. * @since 1.0.0 
  269. */ 
  270. public function before_save() { 
  271. parent::before_save(); 
  272. $this->description = $this->message; 
  273.  
  274. /** 
  275. * Hook process communication actions. 
  276. * 
  277. * Used by child classes to process communication queue. 
  278. * 
  279. * @since 1.0.0 
  280. */ 
  281. public function after_load() { 
  282. parent::after_load(); 
  283.  
  284. $this->message = $this->description; 
  285. if ( $this->enabled ) { 
  286. $this->add_action( 
  287. 'ms_cron_process_communications',  
  288. 'process_communication' 
  289. ); 
  290.  
  291. /** 
  292. * Get communication types. 
  293. * 
  294. * @since 1.0.0 
  295. * 
  296. * @return array The communication types. 
  297. */ 
  298. public static function get_communication_types() { 
  299. static $Types = null; 
  300.  
  301. if ( null === $Types ) { 
  302. if ( MS_Model_Addon::is_enabled( MS_Model_Addon::ADDON_AUTO_MSGS_PLUS ) ) { 
  303. $Types = array( 
  304. self::COMM_TYPE_REGISTRATION,  
  305. self::COMM_TYPE_REGISTRATION_FREE,  
  306. self::COMM_TYPE_RENEWED,  
  307. self::COMM_TYPE_INVOICE,  
  308. self::COMM_TYPE_BEFORE_FINISHES,  
  309. self::COMM_TYPE_FINISHED,  
  310. self::COMM_TYPE_AFTER_FINISHES,  
  311. self::COMM_TYPE_CANCELLED,  
  312. self::COMM_TYPE_BEFORE_TRIAL_FINISHES,  
  313. self::COMM_TYPE_INFO_UPDATE,  
  314. self::COMM_TYPE_CREDIT_CARD_EXPIRE,  
  315. self::COMM_TYPE_FAILED_PAYMENT,  
  316. self::COMM_TYPE_BEFORE_PAYMENT_DUE,  
  317. self::COMM_TYPE_AFTER_PAYMENT_DUE,  
  318. ); 
  319. } else { 
  320. $Types = array( 
  321. self::COMM_TYPE_REGISTRATION,  
  322. self::COMM_TYPE_INVOICE,  
  323. self::COMM_TYPE_FINISHED,  
  324. self::COMM_TYPE_CANCELLED,  
  325. self::COMM_TYPE_INFO_UPDATE,  
  326. self::COMM_TYPE_CREDIT_CARD_EXPIRE,  
  327. self::COMM_TYPE_FAILED_PAYMENT,  
  328. ); 
  329.  
  330. return apply_filters( 
  331. 'ms_model_communication_get_communication_types',  
  332. $Types 
  333. ); 
  334.  
  335. /** 
  336. * Get Communication types and respective classes. 
  337. * 
  338. * @since 1.0.0 
  339. * 
  340. * @return array { 
  341. * Return array of $type => $class_name. 
  342. * 
  343. * @type string $type The communication type. 
  344. * @type string $class_name The class name of the communication type. 
  345. * } 
  346. */ 
  347. public static function get_communication_type_classes() { 
  348. static $type_classes; 
  349.  
  350. if ( empty( $type_classes ) ) { 
  351. $type_classes = array( 
  352. self::COMM_TYPE_REGISTRATION => 'MS_Model_Communication_Registration',  
  353. self::COMM_TYPE_REGISTRATION_FREE => 'MS_Model_Communication_Registration_Free',  
  354. self::COMM_TYPE_RENEWED => 'MS_Model_Communication_Renewed',  
  355. self::COMM_TYPE_INVOICE => 'MS_Model_Communication_Invoice',  
  356. self::COMM_TYPE_BEFORE_FINISHES => 'MS_Model_Communication_Before_Finishes',  
  357. self::COMM_TYPE_FINISHED => 'MS_Model_Communication_Finished',  
  358. self::COMM_TYPE_AFTER_FINISHES => 'MS_Model_Communication_After_Finishes',  
  359. self::COMM_TYPE_CANCELLED => 'MS_Model_Communication_Cancelled',  
  360. self::COMM_TYPE_BEFORE_TRIAL_FINISHES => 'MS_Model_Communication_Before_Trial_Finishes',  
  361. self::COMM_TYPE_INFO_UPDATE => 'MS_Model_Communication_Info_Update',  
  362. self::COMM_TYPE_CREDIT_CARD_EXPIRE => 'MS_Model_Communication_Credit_Card_Expire',  
  363. self::COMM_TYPE_FAILED_PAYMENT => 'MS_Model_Communication_Failed_Payment',  
  364. self::COMM_TYPE_BEFORE_PAYMENT_DUE => 'MS_Model_Communication_Before_Payment_Due',  
  365. self::COMM_TYPE_AFTER_PAYMENT_DUE => 'MS_Model_Communication_After_Payment_Due',  
  366. ); 
  367.  
  368. return apply_filters( 
  369. 'ms_model_communication_get_communication_type_classes',  
  370. $type_classes 
  371. ); 
  372.  
  373. /** 
  374. * Get Communication types and respective titles. 
  375. * 
  376. * @since 1.0.0 
  377. * 
  378. * @return array { 
  379. * Return array of $type => $title. 
  380. * 
  381. * @type string $type The communication type. 
  382. * @type string $title The title of the communication type. 
  383. * } 
  384. */ 
  385. public static function get_communication_type_titles() { 
  386. static $type_titles; 
  387.  
  388. if ( empty( $type_titles ) ) { 
  389. $type_titles = array( 
  390. self::COMM_TYPE_REGISTRATION => __( 'Signup - Completed with payment', MS_TEXT_DOMAIN ),  
  391. self::COMM_TYPE_REGISTRATION_FREE => __( 'Signup - Completed (free membership)', MS_TEXT_DOMAIN ),  
  392. self::COMM_TYPE_RENEWED => __( 'Subscription - Renewed', MS_TEXT_DOMAIN ),  
  393. self::COMM_TYPE_BEFORE_FINISHES => __( 'Subscription - Before expires', MS_TEXT_DOMAIN ),  
  394. self::COMM_TYPE_FINISHED => __( 'Subscription - Expired', MS_TEXT_DOMAIN ),  
  395. self::COMM_TYPE_AFTER_FINISHES => __( 'Subscription - After expired', MS_TEXT_DOMAIN ),  
  396. self::COMM_TYPE_CANCELLED => __( 'Subscription - Cancelled', MS_TEXT_DOMAIN ),  
  397. self::COMM_TYPE_BEFORE_TRIAL_FINISHES => __( 'Subscription - Trial finished', MS_TEXT_DOMAIN ),  
  398. self::COMM_TYPE_INFO_UPDATE => __( 'Payment - Profile updated', MS_TEXT_DOMAIN ),  
  399. self::COMM_TYPE_CREDIT_CARD_EXPIRE => __( 'Payment - Credit Card expires', MS_TEXT_DOMAIN ),  
  400. self::COMM_TYPE_INVOICE => __( 'Payment - Receipt/Invoice', MS_TEXT_DOMAIN ),  
  401. self::COMM_TYPE_FAILED_PAYMENT => __( 'Payment - Failed', MS_TEXT_DOMAIN ),  
  402. self::COMM_TYPE_BEFORE_PAYMENT_DUE => __( 'Payment - Before due', MS_TEXT_DOMAIN ),  
  403. self::COMM_TYPE_AFTER_PAYMENT_DUE => __( 'Payment - After due', MS_TEXT_DOMAIN ),  
  404. ); 
  405.  
  406. foreach ( $type_titles as $type => $title ) { 
  407. if ( ! self::is_valid_communication_type( $type ) ) { 
  408. unset( $type_titles[ $type ] ); 
  409.  
  410. return apply_filters( 
  411. 'ms_model_communication_get_communication_type_titles',  
  412. $type_titles 
  413. ); 
  414.  
  415. /** 
  416. * Validate communication type. 
  417. * 
  418. * @since 1.0.0 
  419. * 
  420. * @param string $type The type to validate. 
  421. * @return bool True if is valid. 
  422. */ 
  423. public static function is_valid_communication_type( $type ) { 
  424. $valid = ! empty( $type ) 
  425. && in_array( $type, self::get_communication_types() ); 
  426.  
  427. return apply_filters( 
  428. 'ms_model_communication_is_valid_communication_type',  
  429. $valid,  
  430. $type 
  431. ); 
  432.  
  433. /** 
  434. * Get communication type object. 
  435. * 
  436. * Load from DB if exists, create a new one if not. 
  437. * 
  438. * @since 1.0.0 
  439. * 
  440. * @param string $type The type of the communication. 
  441. * @param boolean $create_if_not_exists Optional. Flag to create a comm type if not exists. 
  442. * @return MS_Model_Communication The communication object. 
  443. */ 
  444. public static function get_communication( $type, $create_if_not_exists = false ) { 
  445. $model = null; 
  446.  
  447. if ( self::is_valid_communication_type( $type ) ) { 
  448. if ( ! empty( self::$communications[ $type ] ) ) { 
  449. $model = self::$communications[ $type ]; 
  450. } else { 
  451. $args = array( 
  452. 'post_type' => self::get_post_type(),  
  453. 'post_status' => 'any',  
  454. 'fields' => 'ids',  
  455. 'order' => 'DESC',  
  456. 'orderby' => 'ID',  
  457. 'meta_query' => array( 
  458. array( 
  459. 'key' => 'type',  
  460. 'value' => $type,  
  461. 'compare' => '=',  
  462. ),  
  463. ); 
  464.  
  465. $args = apply_filters( 
  466. 'ms_model_communication_get_communication_args',  
  467. $args 
  468. ); 
  469.  
  470. MS_Factory::select_blog(); 
  471. $query = new WP_Query( $args ); 
  472. $item = $query->get_posts(); 
  473. MS_Factory::revert_blog(); 
  474.  
  475. $comm_classes = self::get_communication_type_classes(); 
  476.  
  477. if ( ! empty( $item[0] ) ) { 
  478. $model = MS_Factory::load( 
  479. $comm_classes[$type],  
  480. $item[0] 
  481. ); 
  482. } elseif ( $create_if_not_exists ) { 
  483. $model = self::communication_factory( 
  484. $type,  
  485. $comm_classes[$type] 
  486. ); 
  487.  
  488. return apply_filters( 
  489. 'ms_model_communication_get_communication_' . $type,  
  490. $model 
  491. ); 
  492.  
  493. /** 
  494. * Communication factory. 
  495. * 
  496. * Create a new communication object. 
  497. * 
  498. * @since 1.0.0 
  499. * 
  500. * @param string $type The type of the communication. 
  501. * @param string $class The communication type class. 
  502. * @return MS_Model_Communication The communication object. 
  503. */ 
  504. public static function communication_factory( $type, $class ) { 
  505. $model = MS_Factory::create( $class ); 
  506. $model->reset_to_default(); 
  507.  
  508. return apply_filters( 
  509. 'ms_model_communication_communication_factory',  
  510. $model,  
  511. $type,  
  512. $class 
  513. ); 
  514.  
  515. /** 
  516. * Communication default communication. 
  517. * 
  518. * To be overridden by children classes creating a new object with the default subject, message, enabled, etc. 
  519. * 
  520. * @since 1.0.0 
  521. */ 
  522. public function reset_to_default() { 
  523. do_action( 
  524. 'ms_model_communication_reset_to_default',  
  525. $this->type,  
  526. $this 
  527. ); 
  528.  
  529. /** 
  530. * Retrieve and return all communication types objects. 
  531. * 
  532. * @since 1.0.0 
  533. * 
  534. * @param boolean $create_if_not_exists Optional. Flag to create a comm type if not exists. 
  535. * @return MS_Model_Communication[] The communication objects array. 
  536. */ 
  537. public static function load_communications( $create_if_not_exists = false ) { 
  538. if ( empty( self::$communications ) ) { 
  539. $comm_types = self::get_communication_types(); 
  540.  
  541. foreach ( $comm_types as $type ) { 
  542. $comm = self::get_communication( $type, $create_if_not_exists ); 
  543.  
  544. if ( ! empty( $comm ) ) { 
  545. self::$communications[ $type ] = $comm; 
  546.  
  547. return apply_filters( 
  548. 'ms_model_communication_communication_set_factory',  
  549. self::$communications 
  550. ); 
  551.  
  552. /** 
  553. * Get communication description. 
  554. * 
  555. * Override it in children classes. 
  556. * 
  557. * @since 1.0.0 
  558. * 
  559. * @return string The description. 
  560. */ 
  561. public function get_description() { 
  562. $description = __( 'Override this description in child class', MS_TEXT_DOMAIN ); 
  563.  
  564. return apply_filters( 
  565. 'ms_model_communication_get_description',  
  566. $description 
  567. ); 
  568.  
  569. /** 
  570. * Populates the field title/description of the Period before/after field 
  571. * in the admin settings. 
  572. * 
  573. * Override this in child classes to customize the label. 
  574. * 
  575. * @since 1.1.0.9 
  576. * @param array $field A HTML definition, passed to lib2()->html->element() 
  577. */ 
  578. public function set_period_name( $field ) { 
  579. $field['title'] = __( 'Period before/after', MS_TEXT_DOMAIN ); 
  580.  
  581. return $field; 
  582.  
  583. /** 
  584. * Process communication. 
  585. * 
  586. * Send email and manage queue. 
  587. * 
  588. * @since 1.0.0 
  589. */ 
  590. public function process_communication() { 
  591. do_action( 
  592. 'ms_model_communication_process_communication_before',  
  593. $this 
  594. ); 
  595.  
  596. /** 
  597. * Use `define( 'MS_STOP_EMAILS', true );` in wp-config.php to prevent 
  598. * Membership2 from sending *any* emails to users. 
  599. * Also any currently enqueued message is removed from the queue 
  600. * 
  601. * @since 1.1.0.5 
  602. */ 
  603. if ( MS_Plugin::get_modifier( 'MS_STOP_EMAILS' ) ) { 
  604. $this->queue = array(); 
  605.  
  606. if ( $this->enabled && ! $this->check_object_lock() ) { 
  607. $this->set_object_lock(); 
  608.  
  609. // Max emails that are sent in one process call. 
  610. $max_emails_qty = apply_filters( 
  611. 'ms_model_communication_process_communication_max_email_qty',  
  612. 50 
  613. ); 
  614. $count = 0; 
  615.  
  616. // Email-processing timeout, in seconds. 
  617. $time_limit = apply_filters( 
  618. 'ms_model_communication_process_communication_time_limit',  
  619. 10 
  620. ); 
  621. $start_time = time(); 
  622.  
  623. foreach ( $this->queue as $subscription_id => $date ) { 
  624. if ( time() > $start_time + $time_limit 
  625. || ++$count > $max_emails_qty 
  626. ) { 
  627. break; 
  628.  
  629. $subscription = MS_Factory::load( 'MS_Model_Relationship', $subscription_id ); 
  630. if ( $this->send_message( $subscription ) ) { 
  631. $this->remove_from_queue( $subscription_id ); 
  632. } else { 
  633. do_action( 
  634. 'lib2_debug_log',  
  635. sprintf( 
  636. __( '[error: Communication email failed] comm_type=%s, subscription_id=%s, user_id=%s', MS_TEXT_DOMAIN ),  
  637. $this->type,  
  638. $subscription->id,  
  639. $subscription->user_id 
  640. ); 
  641.  
  642. $this->save(); 
  643. $this->delete_object_lock(); 
  644.  
  645. do_action( 'ms_model_communication_process_communication_after', $this ); 
  646.  
  647. /** 
  648. * Enqueue a message in the "send queue". 
  649. * 
  650. * Action handler hooked up in child classes. 
  651. * 
  652. * Related Action Hooks: 
  653. * - ms_model_event_{$comm_type} 
  654. * 
  655. * @since 1.0.0 
  656. * 
  657. * @param MS_Model_Event $event The event object. 
  658. * @param MS_Model_Relationship $ms_relationship The membership relationship to send message to. 
  659. */ 
  660. public function enqueue_messages( $event, $ms_relationship ) { 
  661. do_action( 'ms_model_communication_enqueue_messages_before', $this ); 
  662.  
  663. if ( $this->enabled ) { 
  664. $this->add_to_queue( $ms_relationship->id ); 
  665. $this->save(); 
  666.  
  667. do_action( 'ms_model_communication_enqueue_messages_after', $this ); 
  668.  
  669. /** 
  670. * Add a message in the "send queue". 
  671. * 
  672. * @since 1.0.0 
  673. * 
  674. * @param int $subscription_id The membership relationship ID to add to queue. 
  675. */ 
  676. public function add_to_queue( $subscription_id ) { 
  677. do_action( 'ms_model_communication_add_to_queue_before', $this ); 
  678.  
  679. /** 
  680. * Documented in process_communication() 
  681. * 
  682. * @since 1.1.0.5 
  683. */ 
  684. if ( MS_Plugin::get_modifier( 'MS_STOP_EMAILS' ) ) { 
  685. $subscription = MS_Factory::load( 'MS_Model_Relationship', $subscription_id ); 
  686. do_action( 
  687. 'lib2_debug_log',  
  688. sprintf( 
  689. 'Following Email was not sent: "%s" to user "%s".',  
  690. $this->type,  
  691. $subscription->user_id 
  692. ); 
  693.  
  694. return false; 
  695.  
  696. if ( $this->enabled 
  697. && ! array_key_exists( $subscription_id, $this->queue ) 
  698. ) { 
  699. $can_add = true; 
  700.  
  701. /** 
  702. * Verify if it was recently sent. 
  703. * Uncomment this if needing less emails. 
  704. */ 
  705. /** 
  706. if ( array_key_exists( $subscription_id, $this->sent_queue ) ) { 
  707. $min_days_before_resend = apply_filters( 'ms_model_communication_add_to_queue_min_days_before_resend', 1 ); 
  708. $sent_date = $this->sent_queue[ $subscription_id ]; 
  709. $now = MS_Helper_Period::current_date( MS_Helper_Period::DATE_FORMAT_SHORT ); 
  710.   
  711. if ( MS_Helper_Period::subtract_dates( $now, $sent_date ) < $min_days_before_resend ) { 
  712. $can_add = false; 
  713. } 
  714. } 
  715. */ 
  716.  
  717. if ( $can_add ) { 
  718. $this->queue[ $subscription_id ] = MS_Helper_Period::current_date( 
  719. MS_Helper_Period::DATE_FORMAT_SHORT 
  720. ); 
  721.  
  722. do_action( 'ms_model_communication_add_to_queue_after', $this ); 
  723.  
  724. /** 
  725. * Remove from queue. 
  726. * 
  727. * Delete history of sent messages after max is reached. 
  728. * 
  729. * @since 1.0.0 
  730. * 
  731. * @param int $ms_relationship_id The membership relationship ID to remove from queue. 
  732. */ 
  733. public function remove_from_queue( $ms_relationship_id ) { 
  734. do_action( 'ms_model_communication_remove_from_queue_before', $this ); 
  735.  
  736. $this->sent_queue[ $ms_relationship_id ] = MS_Helper_Period::current_date( 
  737. MS_Helper_Period::DATE_FORMAT_SHORT 
  738. ); 
  739. unset( $this->queue[ $ms_relationship_id ] ); 
  740.  
  741. $max_history = apply_filters( 
  742. 'ms_model_communication_sent_queue_max_history',  
  743. 300 
  744. ); 
  745.  
  746. // Delete history 
  747. if ( count( $this->sent_queue ) > $max_history ) { 
  748. $this->sent_queue = array_slice( 
  749. $this->sent_queue,  
  750. -100,  
  751. $max_history,  
  752. true 
  753. ); 
  754.  
  755. do_action( 'ms_model_communication_remove_from_queue_after', $this ); 
  756.  
  757. /** 
  758. * Send email message. 
  759. * 
  760. * Delete history of sent messages after max is reached. 
  761. * 
  762. * @since 1.0.0 
  763. * 
  764. * @param MS_Model_Relationship $subscription The membership relationship to send message to. 
  765. * @return bool True if successfully sent email. 
  766. */ 
  767. public function send_message( $subscription ) { 
  768. do_action( 
  769. 'ms_model_communication_send_message_before',  
  770. $subscription,  
  771. $this 
  772. ); 
  773.  
  774. $sent = false; 
  775.  
  776. if ( $this->enabled ) { 
  777. $wp_user = new WP_User( $subscription->user_id ); 
  778.  
  779. if ( ! is_email( $wp_user->user_email ) ) { 
  780. do_action( 
  781. 'lib2_debug_log',  
  782. sprintf( 
  783. 'Invalid user email. User_id: %1$s, email: %2$s',  
  784. $subscription->user_id,  
  785. $wp_user->user_email 
  786. ); 
  787. return false; 
  788.  
  789. $comm_vars = $this->get_comm_vars( $subscription, $wp_user ); 
  790.  
  791. // Replace the email variables. 
  792. $message = str_replace( 
  793. array_keys( $comm_vars ),  
  794. array_values( $comm_vars ),  
  795. stripslashes( $this->message ) 
  796. ); 
  797.  
  798. $subject = str_replace( 
  799. array_keys( $comm_vars ),  
  800. array_values( $comm_vars ),  
  801. stripslashes( $this->subject ) 
  802. ); 
  803.  
  804. $html_message = wpautop( $message ); 
  805. $text_message = strip_tags( preg_replace( '/\<a .*?href="(.*?)".*?\>.*?\<\/a\>/is', '$0 [$1]', $message ) ); 
  806. $subject = strip_tags( preg_replace( '/\<a .*?href="(.*?)".*?\>.*?\<\/a\>/is', '$0 [$1]', $subject ) ); 
  807.  
  808. $message = $text_message; 
  809.  
  810. if ( 'text/html' == $this->get_mail_content_type() ) { 
  811. $this->add_filter( 'wp_mail_content_type', 'get_mail_content_type' ); 
  812. $message = $html_message; 
  813.  
  814. $recipients = array( $wp_user->user_email ); 
  815. if ( $this->cc_enabled ) { 
  816. $recipients[] = $this->cc_email; 
  817.  
  818. $admin_emails = MS_Model_Member::get_admin_user_emails(); 
  819. $headers = ''; 
  820.  
  821. if ( ! empty( $admin_emails[0] ) ) { 
  822. $headers = array( 
  823. sprintf( 'From: %s <%s> ', get_option( 'blogname' ), $admin_emails[0] ) 
  824. ); 
  825.  
  826. $recipients = apply_filters( 
  827. 'ms_model_communication_send_message_recipients',  
  828. $recipients,  
  829. $this,  
  830. $subscription 
  831. ); 
  832. $html_message = apply_filters( 
  833. 'ms_model_communication_send_message_html_message',  
  834. $html_message,  
  835. $this,  
  836. $subscription 
  837. ); 
  838. $text_message = apply_filters( 
  839. 'ms_model_communication_send_message_text_message',  
  840. $text_message,  
  841. $this,  
  842. $subscription 
  843. ); 
  844. $subject = apply_filters( 
  845. 'ms_model_communication_send_message_subject',  
  846. $subject,  
  847. $this,  
  848. $subscription 
  849. ); 
  850. $headers = apply_filters( 
  851. 'ms_model_communication_send_message_headers',  
  852. $headers,  
  853. $this,  
  854. $subscription 
  855. ); 
  856.  
  857. /** 
  858. * Send the mail. 
  859. * wp_mail will not throw an error, so no error-suppression/handling 
  860. * is required here. On error the function response is FALSE. 
  861. */ 
  862. $sent = wp_mail( $recipients, $subject, $message, $headers ); 
  863.  
  864. // Log the outgoing email. 
  865. do_action( 
  866. 'lib2_debug_log',  
  867. sprintf( 
  868. 'Sent email [%s] to <%s>: %s',  
  869. $this->type,  
  870. implode( '>, <', $recipients ),  
  871. $sent ? 'OK' : 'ERR' 
  872. ); 
  873.  
  874. /** 
  875. // -- Debugging code -- 
  876. MS_Helper_Debug::log( 
  877. sprintf( 
  878. "Variables:\n%s",  
  879. print_r( $comm_vars, true ) 
  880. ) 
  881. ); 
  882. //**/ 
  883.  
  884. if ( 'text/html' == $this->get_mail_content_type() ) { 
  885. $this->remove_filter( 
  886. 'wp_mail_content_type',  
  887. 'get_mail_content_type' 
  888. ); 
  889.  
  890. do_action( 
  891. 'ms_model_communication_send_message_before',  
  892. $subscription,  
  893. $this 
  894. ); 
  895.  
  896. return $sent; 
  897.  
  898. /** 
  899. * Replace comm_vars with corresponding values. 
  900. * 
  901. * @since 1.0.0 
  902. * 
  903. * @param MS_Model_Relationship $subscription The membership relationship to send message to. 
  904. * @param WP_User $wp_user The wordpress user object to get info from. 
  905. * @return array { 
  906. * Returns array of ( $var_name => $var_replace ). 
  907. * 
  908. * @type string $var_name The variable name to replace. 
  909. * @type string $var_replace The variable corresponding replace string. 
  910. * } 
  911. */ 
  912. public function get_comm_vars( $subscription, $wp_user ) { 
  913. $currency = MS_Plugin::instance()->settings->currency . ' '; 
  914. $membership = $subscription->get_membership(); 
  915.  
  916. $invoice = null; 
  917.  
  918. // First try to fetch the current invoice. 
  919. $invoice = $subscription->get_current_invoice( false ); 
  920. $prev_invoice = $subscription->get_previous_invoice(); 
  921.  
  922. // If no current invoice exists then fetch the previous invoice. 
  923. if ( empty( $invoice ) ) { 
  924. $invoice = $prev_invoice; 
  925.  
  926. $comm_vars = apply_filters( 
  927. 'ms_model_communication_comm_vars',  
  928. $this->comm_vars 
  929. ); 
  930.  
  931. foreach ( $comm_vars as $key => $description ) { 
  932. switch ( $key ) { 
  933. case self::COMM_VAR_BLOG_NAME: 
  934. $comm_vars[ $key ] = get_option( 'blogname' ); 
  935. break; 
  936.  
  937. case self::COMM_VAR_BLOG_URL: 
  938. $comm_vars[ $key ] = get_option( 'home' ); 
  939. break; 
  940.  
  941. case self::COMM_VAR_USERNAME: 
  942. $comm_vars[ $key ] = $wp_user->user_login; 
  943. break; 
  944.  
  945. case self::COMM_VAR_USER_DISPLAY_NAME: 
  946. $comm_vars[ $key ] = $wp_user->display_name; 
  947. break; 
  948.  
  949. case self::COMM_VAR_USER_FIRST_NAME: 
  950. $comm_vars[ $key ] = $wp_user->user_firstname; 
  951. break; 
  952.  
  953. case self::COMM_VAR_USER_LAST_NAME: 
  954. $comm_vars[ $key ] = $wp_user->user_lastname; 
  955. break; 
  956.  
  957. case self::COMM_VAR_NET_NAME: 
  958. $comm_vars[ $key ] = get_site_option( 'site_name' ); 
  959. break; 
  960.  
  961. case self::COMM_VAR_NET_URL: 
  962. $comm_vars[ $key ] = get_site_option( 'siteurl' ); 
  963. break; 
  964.  
  965. case self::COMM_VAR_MS_NAME: 
  966. if ( $membership->name ) { 
  967. $comm_vars[ $key ] = $membership->name; 
  968. } else { 
  969. $comm_vars[ $key ] = ''; 
  970. break; 
  971.  
  972. case self::COMM_VAR_MS_INVOICE: 
  973. if ( isset( $invoice ) 
  974. && ( $invoice->total > 0 || $invoice->uses_trial ) 
  975. ) { 
  976. $attr = array( 'post_id' => $invoice->id, 'pay_button' => 0 ); 
  977. $scode = MS_Plugin::instance()->controller->controllers['membership_shortcode']; 
  978. $comm_vars[ $key ] = $scode->membership_invoice( $attr ); 
  979. } else { 
  980. $comm_vars[ $key ] = ''; 
  981. break; 
  982.  
  983. case self::COMM_VAR_MS_ACCOUNT_PAGE_URL: 
  984. $comm_vars[ $key ] = sprintf( 
  985. '<a href="%s">%s</a>',  
  986. MS_Model_Pages::get_page_url( MS_Model_Pages::MS_PAGE_ACCOUNT ),  
  987. __( 'account page', MS_TEXT_DOMAIN ) 
  988. ); 
  989. break; 
  990.  
  991. case self::COMM_VAR_MS_REMAINING_DAYS: 
  992. $days = $subscription->get_remaining_period(); 
  993. $comm_vars[ $key ] = sprintf( 
  994. __( '%s day%s', MS_TEXT_DOMAIN ),  
  995. $days,  
  996. abs( $days ) > 1 ? 's': '' 
  997. ); 
  998. break; 
  999.  
  1000. case self::COMM_VAR_MS_REMAINING_TRIAL_DAYS: 
  1001. $days = $subscription->get_remaining_trial_period(); 
  1002. $comm_vars[ $key ] = sprintf( 
  1003. __( '%s day%s', MS_TEXT_DOMAIN ),  
  1004. $days,  
  1005. abs( $days ) > 1 ? 's': '' 
  1006. ); 
  1007. break; 
  1008.  
  1009. case self::COMM_VAR_MS_EXPIRY_DATE: 
  1010. $comm_vars[ $key ] = $subscription->expire_date; 
  1011. break; 
  1012.  
  1013. $comm_vars[ $key ] = apply_filters( 
  1014. 'ms_model_communication_send_message_comm_var_' . $key,  
  1015. $comm_vars[ $key ],  
  1016. $subscription 
  1017. ); 
  1018.  
  1019. return apply_filters( 
  1020. 'ms_model_communication_get_comm_vars',  
  1021. $comm_vars 
  1022. ); 
  1023.  
  1024. /** 
  1025. * Get Email content type. 
  1026. * 
  1027. * Eg. text/html, text. 
  1028. * 
  1029. * @since 1.0.0 
  1030. * 
  1031. * @return string 
  1032. */ 
  1033. public function get_mail_content_type() { 
  1034. $this->content_type = apply_filters( 
  1035. 'ms_model_communication_set_html_content_type',  
  1036. 'text/html' 
  1037. ); 
  1038.  
  1039. return $this->content_type; 
  1040.  
  1041. /** 
  1042. * Validate specific property before set. 
  1043. * 
  1044. * @since 1.0.0 
  1045. * @param string $name The name of a property to associate. 
  1046. * @param mixed $value The value of a property. 
  1047. */ 
  1048. public function __set( $property, $value ) { 
  1049. if ( property_exists( $this, $property ) ) { 
  1050. switch ( $property ) { 
  1051. case 'type': 
  1052. if ( $this->is_valid_communication_type( $value ) ) { 
  1053. $this->$property = $value; 
  1054. break; 
  1055.  
  1056. case 'subject': 
  1057. $this->$property = sanitize_text_field( $value ); 
  1058. break; 
  1059.  
  1060. case 'cc_email': 
  1061. if ( is_email( $value ) ) { 
  1062. $this->$property = $value; 
  1063. break; 
  1064.  
  1065. case 'enabled': 
  1066. case 'cc_enabled': 
  1067. $this->$property = lib2()->is_true( $value ); 
  1068. break; 
  1069.  
  1070. case 'period': 
  1071. $this->$property = $this->validate_period( $value ); 
  1072. break; 
  1073.  
  1074. default: 
  1075. $this->$property = $value; 
  1076. break; 
  1077. else { 
  1078. switch ( $property ) { 
  1079. case 'period_unit': 
  1080. $this->period['period_unit'] = $this->validate_period_unit( $value ); 
  1081. break; 
  1082.  
  1083. case 'period_type': 
  1084. $this->period['period_type'] = $this->validate_period_type( $value ); 
  1085. break; 
  1086.  
  1087. do_action( 
  1088. 'ms_model_communication__set_after',  
  1089. $property,  
  1090. $value,  
  1091. $this 
  1092. ); 
  1093.  
  1094. }; 
.