/includes/integrations/class-integration.php

  1. <?php 
  2.  
  3. /** 
  4. * Class MC4WP_Integration 
  5. * 
  6. * Base class for all integrations. 
  7. * 
  8. * Extend this class and implement the `add_hooks` method to get a settings page. 
  9. * 
  10. * @access public 
  11. * @since 3.0 
  12. * @abstract 
  13. */ 
  14. abstract class MC4WP_Integration { 
  15.  
  16. /** 
  17. * @var string Name of this integration. 
  18. */ 
  19. public $name = ''; 
  20.  
  21. /** 
  22. * @var string Description 
  23. */ 
  24. public $description = ''; 
  25.  
  26. /** 
  27. * @var string Slug, used as an unique identifier for this integration. 
  28. */ 
  29. public $slug = ''; 
  30.  
  31. /** 
  32. * @var array Array of settings 
  33. */ 
  34. public $options = array(); 
  35.  
  36. /** 
  37. * @var string Name attribute for the checkbox element. Will be created from slug if empty. 
  38. */ 
  39. protected $checkbox_name = ''; 
  40.  
  41. /** 
  42. * Constructor 
  43. * 
  44. * @param string $slug 
  45. * @param array $options 
  46. */ 
  47. public function __construct( $slug, array $options ) { 
  48. $this->slug = $slug; 
  49. $this->options = $this->parse_options( $options ); 
  50.  
  51. // if checkbox name is not set, set a good custom value 
  52. if( empty( $this->checkbox_name ) ) { 
  53. $this->checkbox_name = '_mc4wp_subscribe_' . $this->slug; 
  54.  
  55. /** 
  56. * Return array of default options 
  57. * 
  58. * @staticvar $defaults 
  59. * @return array 
  60. */ 
  61. protected function get_default_options() { 
  62. static $defaults; 
  63.  
  64. if( ! $defaults ) { 
  65. $defaults = require MC4WP_PLUGIN_DIR . 'config/default-integration-options.php'; 
  66.  
  67. return $defaults; 
  68.  
  69. /** 
  70. * @param array $options 
  71. * 
  72. * @return array 
  73. */ 
  74. protected function parse_options( array $options ) { 
  75. $slug = $this->slug; 
  76.  
  77. $options = array_merge( $this->get_default_options(), $options ); 
  78.  
  79. /** 
  80. * Filters options for a specific integration 
  81. * 
  82. * The dynamic portion of the hook, `$slug`, refers to the slug of the ingration. 
  83. * 
  84. * @param array $integration_options 
  85. * @ignore 
  86. */ 
  87. return (array) apply_filters( 'mc4wp_' . $slug . '_integration_options', $options ); 
  88.  
  89. /** 
  90. * Initialize the integration 
  91. */ 
  92. public function initialize() { 
  93. $this->add_required_hooks(); 
  94. $this->add_hooks(); 
  95.  
  96. /** 
  97. * Adds the required hooks for core functionality, like adding checkbox reset CSS. 
  98. */ 
  99. protected function add_required_hooks() { 
  100. if( $this->options['css'] && ! $this->options['implicit'] ) { 
  101. add_action( 'wp_head', array( $this, 'print_css_reset' ) ); 
  102.  
  103. /** 
  104. * Was integration triggered? 
  105. * 
  106. * Will always return true when integration is implicit. Otherwise, will check value of checkbox. 
  107. * 
  108. * @param int $object_id Useful when overriding method. (optional) 
  109. * @return bool 
  110. */ 
  111. public function triggered( $object_id = null ) { 
  112. return $this->options['implicit'] || $this->checkbox_was_checked(); 
  113.  
  114. /** 
  115. * Adds the hooks which are specific to this integration 
  116. */ 
  117. abstract protected function add_hooks(); 
  118.  
  119. /** 
  120. * Print CSS reset 
  121. * 
  122. * @hooked `wp_head` 
  123. */ 
  124. public function print_css_reset() { 
  125. $suffix = defined( 'SCRIPT_DEBUG' ) ? '' : '.min'; 
  126. $css = file_get_contents( MC4WP_PLUGIN_DIR . 'assets/css/checkbox-reset' . $suffix . '.css' ); 
  127.  
  128. // replace selector by integration specific selector so the css affects just this checkbox 
  129. $css = str_ireplace( '__INTEGRATION_SLUG__', $this->slug, $css ); 
  130.  
  131. printf( '<style type="text/css">%s</style>', $css ); 
  132.  
  133. /** 
  134. * Get the text for the label element 
  135. * 
  136. * @return string 
  137. */ 
  138. public function get_label_text() { 
  139. $integration = $this; 
  140. $label = $this->options['label']; 
  141.  
  142. /** 
  143. * Filters the checkbox label 
  144. * 
  145. * @since 3.0 
  146. * 
  147. * @param string $label 
  148. * @param MC4WP_Integration $integration 
  149. * @ignore 
  150. */ 
  151. $label = (string) apply_filters( 'mc4wp_integration_checkbox_label', $label, $integration ); 
  152. return $label; 
  153.  
  154. /** 
  155. * Was the integration checkbox checked? 
  156. * 
  157. * @return bool 
  158. */ 
  159. public function checkbox_was_checked() { 
  160. $data = $this->get_data(); 
  161. return ( isset( $data[ $this->checkbox_name ] ) && $data[ $this->checkbox_name ] == 1 ); 
  162.  
  163. /** 
  164. * Get a string of attributes for the checkbox element. 
  165. * 
  166. * @return string 
  167. */ 
  168. protected function get_checkbox_attributes() { 
  169.  
  170. $integration = $this; 
  171. $slug = $this->slug; 
  172.  
  173. $attributes = array(); 
  174.  
  175. if( $this->options['precheck'] ) { 
  176. $attributes['checked'] = 'checked'; 
  177.  
  178. /** 
  179. * Filters the attributes array. 
  180. * 
  181. * @param array $attributes 
  182. * @param MC4WP_Integration $integration 
  183. * @ignore 
  184. */ 
  185. $attributes = (array) apply_filters( 'mc4wp_integration_checkbox_attributes', $attributes, $integration ); 
  186.  
  187. /** 
  188. * Filters the attributes array. 
  189. * 
  190. * The dynamic portion of the hook, `$slug`, refers to the slug for this integration. 
  191. * 
  192. * @param array $attributes 
  193. * @param MC4WP_Integration $integration 
  194. * @ignore 
  195. */ 
  196. $attributes = (array) apply_filters( 'mc4wp_integration_' . $slug . '_checkbox_attributes', $attributes, $integration ); 
  197.  
  198. $string = ''; 
  199. foreach( $attributes as $key => $value ) { 
  200. $string .= sprintf( '%s="%s"', $key, esc_attr( $value ) ); 
  201.  
  202. return $string; 
  203.  
  204. /** 
  205. * Outputs a checkbox 
  206. */ 
  207. public function output_checkbox() { 
  208. echo $this->get_checkbox_html(); 
  209.  
  210. /** 
  211. * Get HTML for the checkbox 
  212. * 
  213. * @return string 
  214. */ 
  215. public function get_checkbox_html() { 
  216.  
  217. $show_checkbox = empty( $this->options['implicit'] ); 
  218. $integration_slug = $this->slug; 
  219.  
  220. /** 
  221. * Filters whether to show the sign-up checkbox for this integration. 
  222. * 
  223. * @param bool $show_checkbox 
  224. * @param string $integration_slug 
  225. */ 
  226. $show_checkbox = (bool) apply_filters( 'mc4wp_integration_show_checkbox', $show_checkbox, $integration_slug ); 
  227.  
  228. if( ! $show_checkbox ) { 
  229. return ''; 
  230.  
  231. ob_start(); 
  232.  
  233. echo sprintf( '<!-- MailChimp for WordPress v%s - https://mc4wp.com/ -->', MC4WP_VERSION ); 
  234.  
  235. /** @ignore */ 
  236. do_action( 'mc4wp_integration_before_checkbox_wrapper', $this ); 
  237.  
  238. /** @ignore */ 
  239. do_action( 'mc4wp_integration_'. $this->slug .'_before_checkbox_wrapper', $this ); 
  240.  
  241. $wrapper_tag = $this->options['wrap_p'] ? 'p' : 'span'; 
  242.  
  243. // Hidden field to make sure "0" is sent to server 
  244. echo sprintf( '<input type="hidden" name="%s" value="0" />', esc_attr( $this->checkbox_name ) ); 
  245.  
  246. echo sprintf( '<%s class="mc4wp-checkbox mc4wp-checkbox-%s">', $wrapper_tag, esc_attr( $this->slug ) ); 
  247. echo '<label>'; 
  248. echo sprintf( '<input type="checkbox" name="%s" value="1" %s />', esc_attr( $this->checkbox_name ), $this->get_checkbox_attributes() ); 
  249. echo sprintf( '<span>%s</span>', $this->get_label_text() ); 
  250. echo '</label>'; 
  251. echo sprintf( '</%s>', $wrapper_tag ); 
  252.  
  253. /** @ignore */ 
  254. do_action( 'mc4wp_integration_after_checkbox_wrapper', $this ); 
  255.  
  256. /** @ignore */ 
  257. do_action( 'mc4wp_integration_'. $this->slug .'_after_checkbox_wrapper', $this ); 
  258. echo '<!-- / MailChimp for WordPress -->'; 
  259.  
  260. $html = ob_get_clean(); 
  261. return $html; 
  262.  
  263. /** 
  264. * Get the selected MailChimp lists 
  265. * 
  266. * @return array Array of List ID's 
  267. */ 
  268. public function get_lists() { 
  269.  
  270. $data = $this->get_data(); 
  271. $integration = $this; 
  272. $slug = $this->slug; 
  273.  
  274. // get checkbox lists options 
  275. $lists = $this->options['lists']; 
  276.  
  277. // get lists from request, if set. 
  278. if( ! empty( $data['_mc4wp_lists'] ) ) { 
  279.  
  280. $lists = $data['_mc4wp_lists']; 
  281.  
  282. // ensure lists is an array 
  283. if( ! is_array( $lists ) ) { 
  284. $lists = explode( ', ', $lists ); 
  285. $lists = array_map( 'trim', $lists ); 
  286.  
  287. // allow plugins to filter final lists value 
  288.  
  289. /** 
  290. * This filter is documented elsewhere. 
  291. * 
  292. * @since 2.0 
  293. * @see MC4WP_Form::get_lists 
  294. * @ignore 
  295. */ 
  296. $lists = (array) apply_filters( 'mc4wp_lists', $lists ); 
  297.  
  298. /** 
  299. * Filters the MailChimp lists this integration should subscribe to 
  300. * 
  301. * @since 3.0 
  302. * 
  303. * @param array $lists 
  304. * @param MC4WP_Integration $integration 
  305. */ 
  306. $lists = (array) apply_filters( 'mc4wp_integration_lists', $lists, $integration ); 
  307.  
  308. /** 
  309. * Filters the MailChimp lists a specific integration should subscribe to 
  310. * 
  311. * The dynamic portion of the hook, `$slug`, refers to the slug of the integration. 
  312. * 
  313. * @since 3.0 
  314. * 
  315. * @param array $lists 
  316. * @param MC4WP_Integration $integration 
  317. */ 
  318. $lists = (array) apply_filters( 'mc4wp_integration_' . $slug . '_lists', $lists, $integration ); 
  319.  
  320. return $lists; 
  321.  
  322. /** 
  323. * Makes a subscription request 
  324. * 
  325. * @param array $data 
  326. * @param int $related_object_id 
  327. * 
  328. * @return boolean 
  329. */ 
  330. protected function subscribe( array $data, $related_object_id = 0 ) { 
  331.  
  332. $integration = $this; 
  333. $slug = $this->slug; 
  334. $mailchimp = new MC4WP_MailChimp(); 
  335. $log = $this->get_log(); 
  336. $request= $this->get_request(); 
  337. $list_ids = $this->get_lists(); 
  338.  
  339. /** @var MC4WP_MailChimp_Subscriber $subscriber */ 
  340. $subscriber = null; 
  341. $result = false; 
  342.  
  343. // validate lists 
  344. if( empty( $list_ids ) ) { 
  345. $log->warning( sprintf( '%s > No MailChimp lists were selected', $this->name ) ); 
  346. return false; 
  347.  
  348. /** 
  349. * Filters data for integration requests. 
  350. * 
  351. * @param array $data 
  352. */ 
  353. $data = apply_filters( 'mc4wp_integration_data', $data ); 
  354.  
  355. /** 
  356. * Filters data for a specific integration request. 
  357. * 
  358. * The dynamic portion of the hook, `$slug`, refers to the integration slug. 
  359. * 
  360. * @param array $data 
  361. * @param int $related_object_id 
  362. */ 
  363. $data = apply_filters( "mc4wp_integration_{$slug}_data", $data, $related_object_id ); 
  364.  
  365. /** 
  366. * @ignore 
  367. * @deprecated 4.0 
  368. */ 
  369. $data = apply_filters( 'mc4wp_merge_vars', $data ); 
  370.  
  371. /** 
  372. * @deprecated 4.0 
  373. * @ignore 
  374. */ 
  375. $data = apply_filters( 'mc4wp_integration_merge_vars', $data, $integration ); 
  376.  
  377. /** 
  378. * @deprecated 4.0 
  379. * @ignore 
  380. */ 
  381. $data = apply_filters( "mc4wp_integration_{$slug}_merge_vars", $data, $integration ); 
  382.  
  383. $email_type = mc4wp_get_email_type(); 
  384.  
  385. $mapper = new MC4WP_List_Data_Mapper( $data, $list_ids ); 
  386.  
  387. /** @var MC4WP_MailChimp_Subscriber[] $map */ 
  388. $map = $mapper->map(); 
  389.  
  390. foreach( $map as $list_id => $subscriber ) { 
  391. $subscriber->status = $this->options['double_optin'] ? 'pending' : 'subscribed'; 
  392. $subscriber->email_type = $email_type; 
  393. $subscriber->ip_signup = $request->get_client_ip(); 
  394.  
  395. /** @ignore (documented elsewhere) */ 
  396. $subscriber = apply_filters( 'mc4wp_subscriber_data', $subscriber ); 
  397.  
  398. /** 
  399. * Filters subscriber data before it is sent to MailChimp. Only fires for integration requests. 
  400. * 
  401. * @param MC4WP_MailChimp_Subscriber $subscriber 
  402. */ 
  403. $subscriber = apply_filters( 'mc4wp_integration_subscriber_data', $subscriber ); 
  404.  
  405. /** 
  406. * Filters subscriber data before it is sent to MailChimp. Only fires for integration requests. 
  407. * 
  408. * The dynamic portion of the hook, `$slug`, refers to the integration slug. 
  409. * 
  410. * @param MC4WP_MailChimp_Subscriber $subscriber 
  411. * @param int $related_object_id 
  412. */ 
  413. $subscriber = apply_filters( "mc4wp_integration_{$slug}_subscriber_data", $subscriber, $related_object_id ); 
  414.  
  415. $result = $mailchimp->list_subscribe( $list_id, $subscriber->email_address, $subscriber->to_array(), $this->options['update_existing'], $this->options['replace_interests'] ); 
  416.  
  417. // if result failed, show error message 
  418. if( ! $result ) { 
  419.  
  420. // log error 
  421. if( $mailchimp->get_error_code() == 214 ) { 
  422. $log->warning( sprintf( "%s > %s is already subscribed to the selected list(s)", $this->name, $subscriber->email_address ) ); 
  423. } else { 
  424. $log->error( sprintf( '%s > MailChimp API Error: %s', $this->name, $mailchimp->get_error_message() ) ); 
  425.  
  426. // bail 
  427. return false; 
  428.  
  429. $log->info( sprintf( '%s > Successfully subscribed %s', $this->name, $subscriber->email_address ) ); 
  430.  
  431. /** 
  432. * Runs right after someone is subscribed using an integration 
  433. * 
  434. * @since 3.0 
  435. * 
  436. * @param MC4WP_Integration $integration 
  437. * @param string $email_address 
  438. * @param array $merge_vars 
  439. * @param MC4WP_MailChimp_Subscriber[] $subscriber_data 
  440. * @param int $related_object_id 
  441. */ 
  442. do_action( 'mc4wp_integration_subscribed', $integration, $subscriber->email_address, $subscriber->merge_fields, $map, $related_object_id ); 
  443.  
  444. return $result; 
  445.  
  446. /** 
  447. * Are the required dependencies for this integration installed? 
  448. * 
  449. * @return bool 
  450. */ 
  451. public function is_installed() { 
  452. return false; 
  453.  
  454. /** 
  455. * Which UI elements should we show on the settings page for this integration? 
  456. * 
  457. * @return array 
  458. */ 
  459. public function get_ui_elements() { 
  460. return array_keys( $this->options ); 
  461.  
  462. /** 
  463. * Does integration have the given UI element? 
  464. * 
  465. * @param $element 
  466. * @return bool 
  467. */ 
  468. public function has_ui_element( $element ) { 
  469. $elements = $this->get_ui_elements(); 
  470. return in_array( $element, $elements ); 
  471.  
  472. /** 
  473. * Return a string to the admin settings page for this object (if any) 
  474. * 
  475. * @param int $object_id 
  476. * @return string 
  477. */ 
  478. public function get_object_link( $object_id ) { 
  479. return ''; 
  480.  
  481. /** 
  482. * Get the data for this integration request 
  483. * 
  484. * By default, this will return a combination of all $_GET and $_POST parameters. 
  485. * Override this method if you need data from somewhere else. 
  486. * 
  487. * This data should contain the value of the checkbox (required) 
  488. * and the lists to which should be subscribed (optional) 
  489. * 
  490. * @see MC4WP_Integration::$checkbox_name 
  491. * @see MC4WP_Integration::get_lists 
  492. * @see MC4WP_Integration::checkbox_was_checked 
  493. * 
  494. * @return array 
  495. */ 
  496. public function get_data() { 
  497. $request = mc4wp('request'); 
  498. $data = $request->params->all(); 
  499. return $data; 
  500.  
  501. /** 
  502. * @return MC4WP_Debug_Log 
  503. */ 
  504. protected function get_log() { 
  505. return mc4wp('log'); 
  506.  
  507. /** 
  508. * @return MC4WP_API_v3 
  509. */ 
  510. protected function get_api() { 
  511. return mc4wp('api'); 
  512.  
  513. /** 
  514. * @return MC4WP_Request 
  515. */ 
  516. protected function get_request() { 
  517. return mc4wp('request'); 
  518.  
.