Sin descripción

class-base.php 34KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372
  1. <?php
  2. use \WPForms\Providers\Provider\Settings\FormBuilder;
  3. /**
  4. * Provider class.
  5. *
  6. * @since 1.0.0
  7. */
  8. abstract class WPForms_Provider {
  9. /**
  10. * Provider addon version.
  11. *
  12. * @since 1.0.0
  13. *
  14. * @var string
  15. */
  16. protected $version;
  17. /**
  18. * Provider name.
  19. *
  20. * @since 1.0.0
  21. *
  22. * @var string
  23. */
  24. public $name;
  25. /**
  26. * Provider name in slug format.
  27. *
  28. * @since 1.0.0
  29. *
  30. * @var string
  31. */
  32. public $slug;
  33. /**
  34. * Load priority.
  35. *
  36. * @since 1.0.0
  37. *
  38. * @var int
  39. */
  40. public $priority = 10;
  41. /**
  42. * Store the API connections.
  43. *
  44. * @since 1.0.0
  45. *
  46. * @var mixed
  47. */
  48. public $api = false;
  49. /**
  50. * Service icon.
  51. *
  52. * @since 1.0.0
  53. *
  54. * @var string
  55. */
  56. public $icon;
  57. /**
  58. * Service icon.
  59. *
  60. * @since 1.2.3
  61. *
  62. * @var string
  63. */
  64. public $type;
  65. /**
  66. * Form data and settings.
  67. *
  68. * @since 1.2.3
  69. *
  70. * @var array
  71. */
  72. public $form_data;
  73. /**
  74. * Primary class constructor.
  75. *
  76. * @since 1.0.0
  77. */
  78. public function __construct() {
  79. $this->type = esc_html__( 'Connection', 'wpforms-lite' );
  80. $this->init();
  81. $this->hooks();
  82. }
  83. /**
  84. * Hooks.
  85. *
  86. * @since 1.6.8
  87. */
  88. private function hooks() {
  89. // Add to list of available providers.
  90. add_filter( 'wpforms_providers_available', [ $this, 'register_provider' ], $this->priority, 1 );
  91. // Process builder AJAX requests.
  92. add_action( "wp_ajax_wpforms_provider_ajax_{$this->slug}", [ $this, 'process_ajax' ] );
  93. // Process entry.
  94. add_action( 'wpforms_process_complete', [ $this, 'process_entry' ], 5, 4 );
  95. // Fetch and store the current form data when in the builder.
  96. add_action( 'wpforms_builder_init', [ $this, 'builder_form_data' ] );
  97. // Output builder sidebar.
  98. add_action( 'wpforms_providers_panel_sidebar', [ $this, 'builder_sidebar' ], $this->priority );
  99. // Output builder content.
  100. add_action( 'wpforms_providers_panel_content', [ $this, 'builder_output' ], $this->priority );
  101. // Remove provider from Settings Integrations tab.
  102. add_action( "wp_ajax_wpforms_settings_provider_disconnect_{$this->slug}", [ $this, 'integrations_tab_disconnect' ] );
  103. // Add new provider from Settings Integrations tab.
  104. add_action( "wp_ajax_wpforms_settings_provider_add_{$this->slug}", [ $this, 'integrations_tab_add' ] );
  105. // Add providers sections to the Settings Integrations tab.
  106. add_action( 'wpforms_settings_providers', [ $this, 'integrations_tab_options' ], $this->priority, 2 );
  107. }
  108. /**
  109. * Add to list of registered providers.
  110. *
  111. * @since 1.0.0
  112. *
  113. * @param array $providers Array of all active providers.
  114. *
  115. * @return array
  116. */
  117. public function register_provider( $providers = array() ) {
  118. $providers[ $this->slug ] = $this->name;
  119. return $providers;
  120. }
  121. /**
  122. * Process the Builder AJAX requests.
  123. *
  124. * @since 1.0.0
  125. */
  126. public function process_ajax() {
  127. // Run a security check.
  128. check_ajax_referer( 'wpforms-builder', 'nonce' );
  129. // Check for permissions.
  130. if ( ! wpforms_current_user_can( 'edit_forms' ) ) {
  131. wp_send_json_error(
  132. array(
  133. 'error' => esc_html__( 'You do not have permission', 'wpforms-lite' ),
  134. )
  135. );
  136. }
  137. $name = ! empty( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';
  138. $task = ! empty( $_POST['task'] ) ? sanitize_text_field( wp_unslash( $_POST['task'] ) ) : '';
  139. $id = ! empty( $_POST['id'] ) ? sanitize_text_field( wp_unslash( $_POST['id'] ) ) : '';
  140. $connection_id = ! empty( $_POST['connection_id'] ) ? sanitize_text_field( wp_unslash( $_POST['connection_id'] ) ) : '';
  141. $account_id = ! empty( $_POST['account_id'] ) ? sanitize_text_field( wp_unslash( $_POST['account_id'] ) ) : '';
  142. $list_id = ! empty( $_POST['list_id'] ) ? sanitize_text_field( wp_unslash( $_POST['list_id'] ) ) : '';
  143. $data = ! empty( $_POST['data'] ) ? array_map( 'sanitize_text_field', wp_parse_args( wp_unslash( $_POST['data'] ) ) ) : array(); //phpcs:ignore
  144. /*
  145. * Create new connection.
  146. */
  147. if ( 'new_connection' === $task ) {
  148. $connection = $this->output_connection(
  149. '',
  150. array(
  151. 'connection_name' => $name,
  152. ),
  153. $id
  154. );
  155. wp_send_json_success(
  156. array(
  157. 'html' => $connection,
  158. )
  159. );
  160. }
  161. /*
  162. * Create new Provider account.
  163. */
  164. if ( 'new_account' === $task ) {
  165. $auth = $this->api_auth( $data, $id );
  166. if ( is_wp_error( $auth ) ) {
  167. wp_send_json_error(
  168. array(
  169. 'error' => $auth->get_error_message(),
  170. )
  171. );
  172. } else {
  173. $accounts = $this->output_accounts(
  174. $connection_id,
  175. array(
  176. 'account_id' => $auth,
  177. )
  178. );
  179. wp_send_json_success(
  180. array(
  181. 'html' => $accounts,
  182. )
  183. );
  184. }
  185. }
  186. /*
  187. * Select/Toggle Provider accounts.
  188. */
  189. if ( 'select_account' === $task ) {
  190. $lists = $this->output_lists(
  191. $connection_id,
  192. array(
  193. 'account_id' => $account_id,
  194. )
  195. );
  196. if ( is_wp_error( $lists ) ) {
  197. wp_send_json_error(
  198. array(
  199. 'error' => $lists->get_error_message(),
  200. )
  201. );
  202. } else {
  203. wp_send_json_success(
  204. array(
  205. 'html' => $lists,
  206. )
  207. );
  208. }
  209. }
  210. /*
  211. * Select/Toggle Provider account lists.
  212. */
  213. if ( 'select_list' === $task ) {
  214. $fields = $this->output_fields(
  215. $connection_id,
  216. array(
  217. 'account_id' => $account_id,
  218. 'list_id' => $list_id,
  219. ),
  220. $id
  221. );
  222. if ( is_wp_error( $fields ) ) {
  223. wp_send_json_error(
  224. array(
  225. 'error' => $fields->get_error_message(),
  226. )
  227. );
  228. } else {
  229. $groups = $this->output_groups(
  230. $connection_id,
  231. array(
  232. 'account_id' => $account_id,
  233. 'list_id' => $list_id,
  234. )
  235. );
  236. $conditionals = $this->output_conditionals(
  237. $connection_id,
  238. array(
  239. 'account_id' => $account_id,
  240. 'list_id' => $list_id,
  241. ),
  242. array(
  243. 'id' => absint( $_POST['form_id'] ), //phpcs:ignore
  244. )
  245. );
  246. $options = $this->output_options(
  247. $connection_id,
  248. array(
  249. 'account_id' => $account_id,
  250. 'list_id' => $list_id,
  251. )
  252. );
  253. wp_send_json_success(
  254. array(
  255. 'html' => $groups . $fields . $conditionals . $options,
  256. )
  257. );
  258. }
  259. }
  260. die();
  261. }
  262. /**
  263. * Process and submit entry to provider.
  264. *
  265. * @since 1.0.0
  266. *
  267. * @param array $fields List of fields in a form.
  268. * @param array $entry Submitted entry values.
  269. * @param array $form_data Form data and settings.
  270. * @param int $entry_id Saved entry ID.
  271. */
  272. public function process_entry( $fields, $entry, $form_data, $entry_id ) {
  273. }
  274. /**
  275. * Process conditional fields.
  276. *
  277. * @since 1.0.0
  278. *
  279. * @param array $fields List of fields with their data and settings.
  280. * @param array $entry Submitted entry values.
  281. * @param array $form_data Form data and settings.
  282. * @param array $connection List of connection settings.
  283. *
  284. * @return bool
  285. */
  286. public function process_conditionals( $fields, $entry, $form_data, $connection ) {
  287. if (
  288. empty( $connection['conditional_logic'] ) ||
  289. empty( $connection['conditionals'] ) ||
  290. ! function_exists( 'wpforms_conditional_logic' )
  291. ) {
  292. return true;
  293. }
  294. $process = wpforms_conditional_logic()->process( $fields, $form_data, $connection['conditionals'] );
  295. if ( ! empty( $connection['conditional_type'] ) && $connection['conditional_type'] === 'stop' ) {
  296. $process = ! $process;
  297. }
  298. return $process;
  299. }
  300. /**
  301. * Retrieve all available forms in a field.
  302. *
  303. * Not all fields should be available for merge tags so we compare against a
  304. * white-list. Also some fields, such as Name, should have additional
  305. * variations.
  306. *
  307. * @since 1.0.0
  308. *
  309. * @param object|bool $form
  310. * @param array $whitelist
  311. *
  312. * @return bool|array
  313. */
  314. public function get_form_fields( $form = false, $whitelist = array() ) {
  315. // Accept form (post) object or form ID.
  316. if ( is_object( $form ) ) {
  317. $form = wpforms_decode( $form->post_content );
  318. } elseif ( is_numeric( $form ) ) {
  319. $form = wpforms()->form->get(
  320. $form,
  321. array(
  322. 'content_only' => true,
  323. )
  324. );
  325. }
  326. if ( ! is_array( $form ) || empty( $form['fields'] ) ) {
  327. return false;
  328. }
  329. // White list of field types to allow.
  330. $allowed_form_fields = array(
  331. 'text',
  332. 'textarea',
  333. 'select',
  334. 'radio',
  335. 'checkbox',
  336. 'email',
  337. 'address',
  338. 'url',
  339. 'name',
  340. 'hidden',
  341. 'date-time',
  342. 'phone',
  343. 'number',
  344. );
  345. $allowed_form_fields = apply_filters( 'wpforms_providers_fields', $allowed_form_fields );
  346. $whitelist = ! empty( $whitelist ) ? $whitelist : $allowed_form_fields;
  347. $form_fields = $form['fields'];
  348. foreach ( $form_fields as $id => $form_field ) {
  349. if ( ! in_array( $form_field['type'], $whitelist, true ) ) {
  350. unset( $form_fields[ $id ] );
  351. }
  352. }
  353. return $form_fields;
  354. }
  355. /**
  356. * Get form fields ready for select list options.
  357. *
  358. * In this function we also do the logic to limit certain fields to certain
  359. * provider field types.
  360. *
  361. * @since 1.0.0
  362. *
  363. * @param array $form_fields
  364. * @param string $form_field_type
  365. *
  366. * @return array
  367. */
  368. public function get_form_field_select( $form_fields = array(), $form_field_type = '' ) {
  369. if ( empty( $form_fields ) || empty( $form_field_type ) ) {
  370. return array();
  371. }
  372. $formatted = array();
  373. // Include only specific field types.
  374. foreach ( $form_fields as $id => $form_field ) {
  375. // Email.
  376. if (
  377. 'email' === $form_field_type &&
  378. ! in_array( $form_field['type'], array( 'text', 'email' ), true )
  379. ) {
  380. unset( $form_fields[ $id ] );
  381. }
  382. // Address.
  383. if (
  384. 'address' === $form_field_type &&
  385. ! in_array( $form_field['type'], array( 'address' ), true )
  386. ) {
  387. unset( $form_fields[ $id ] );
  388. }
  389. }
  390. // Format.
  391. foreach ( $form_fields as $id => $form_field ) {
  392. // Complex Name field.
  393. if ( 'name' === $form_field['type'] ) {
  394. // Full Name.
  395. $formatted[] = array(
  396. 'id' => $form_field['id'],
  397. 'key' => 'value',
  398. 'type' => $form_field['type'],
  399. 'subtype' => '',
  400. 'provider_type' => $form_field_type,
  401. 'label' => sprintf(
  402. /* translators: %s - Name field label. */
  403. esc_html__( '%s (Full)', 'wpforms-lite' ),
  404. $form_field['label']
  405. ),
  406. );
  407. // First Name.
  408. if ( strpos( $form_field['format'], 'first' ) !== false ) {
  409. $formatted[] = array(
  410. 'id' => $form_field['id'],
  411. 'key' => 'first',
  412. 'type' => $form_field['type'],
  413. 'subtype' => 'first',
  414. 'provider_type' => $form_field_type,
  415. 'label' => sprintf(
  416. /* translators: %s - Name field label. */
  417. esc_html__( '%s (First)', 'wpforms-lite' ),
  418. $form_field['label']
  419. ),
  420. );
  421. }
  422. // Middle Name.
  423. if ( strpos( $form_field['format'], 'middle' ) !== false ) {
  424. $formatted[] = array(
  425. 'id' => $form_field['id'],
  426. 'key' => 'middle',
  427. 'type' => $form_field['type'],
  428. 'subtype' => 'middle',
  429. 'provider_type' => $form_field_type,
  430. 'label' => sprintf(
  431. /* translators: %s - Name field label. */
  432. esc_html__( '%s (Middle)', 'wpforms-lite' ),
  433. $form_field['label']
  434. ),
  435. );
  436. }
  437. // Last Name.
  438. if ( strpos( $form_field['format'], 'last' ) !== false ) {
  439. $formatted[] = array(
  440. 'id' => $form_field['id'],
  441. 'key' => 'last',
  442. 'type' => $form_field['type'],
  443. 'subtype' => 'last',
  444. 'provider_type' => $form_field_type,
  445. 'label' => sprintf(
  446. /* translators: %s - Name field label. */
  447. esc_html__( '%s (Last)', 'wpforms-lite' ),
  448. $form_field['label']
  449. ),
  450. );
  451. }
  452. } else {
  453. // All other fields.
  454. $formatted[] = array(
  455. 'id' => $form_field['id'],
  456. 'key' => 'value',
  457. 'type' => $form_field['type'],
  458. 'subtype' => '',
  459. 'provider_type' => $form_field_type,
  460. 'label' => $form_field['label'],
  461. );
  462. }
  463. }
  464. return $formatted;
  465. }
  466. /************************************************************************
  467. * API methods - these methods interact directly with the provider API. *
  468. ************************************************************************/
  469. /**
  470. * Authenticate with the provider API.
  471. *
  472. * @since 1.0.0
  473. *
  474. * @param array $data
  475. * @param string $form_id
  476. *
  477. * @return mixed id or error object
  478. */
  479. public function api_auth( $data = array(), $form_id = '' ) {
  480. }
  481. /**
  482. * Establish connection object to provider API.
  483. *
  484. * @since 1.0.0
  485. *
  486. * @param string $account_id
  487. *
  488. * @return mixed array or error object
  489. */
  490. public function api_connect( $account_id ) {
  491. }
  492. /**
  493. * Retrieve provider account lists.
  494. *
  495. * @since 1.0.0
  496. *
  497. * @param string $connection_id
  498. * @param string $account_id
  499. *
  500. * @return mixed array or error object
  501. */
  502. public function api_lists( $connection_id = '', $account_id = '' ) {
  503. }
  504. /**
  505. * Retrieve provider account list groups.
  506. *
  507. * @since 1.0.0
  508. *
  509. * @param string $connection_id
  510. * @param string $account_id
  511. * @param string $list_id
  512. *
  513. * @return mixed array or error object
  514. */
  515. public function api_groups( $connection_id = '', $account_id = '', $list_id = '' ) {
  516. }
  517. /**
  518. * Retrieve provider account list fields.
  519. *
  520. * @since 1.0.0
  521. *
  522. * @param string $connection_id
  523. * @param string $account_id
  524. * @param string $list_id
  525. *
  526. * @return mixed array or error object
  527. */
  528. public function api_fields( $connection_id = '', $account_id = '', $list_id = '' ) {
  529. }
  530. /*************************************************************************
  531. * Output methods - these methods generally return HTML for the builder. *
  532. *************************************************************************/
  533. /**
  534. * Connection HTML.
  535. *
  536. * This method compiles all the HTML necessary for a connection to a provider.
  537. *
  538. * @since 1.0.0
  539. *
  540. * @param string $connection_id
  541. * @param array $connection
  542. * @param mixed $form Form id or form data.
  543. *
  544. * @return string
  545. */
  546. public function output_connection( $connection_id = '', $connection = array(), $form = '' ) {
  547. if ( empty( $connection_id ) ) {
  548. $connection_id = 'connection_' . uniqid();
  549. }
  550. if ( empty( $connection ) || empty( $form ) ) {
  551. return '';
  552. }
  553. $output = sprintf( '<div class="wpforms-provider-connection" data-provider="%s" data-connection_id="%s">', $this->slug, $connection_id );
  554. $output .= $this->output_connection_header( $connection_id, $connection );
  555. $output .= $this->output_auth();
  556. $output .= $this->output_accounts( $connection_id, $connection );
  557. $lists = $this->output_lists( $connection_id, $connection );
  558. $output .= ! is_wp_error( $lists ) ? $lists : '';
  559. $output .= $this->output_groups( $connection_id, $connection );
  560. $fields = $this->output_fields( $connection_id, $connection, $form );
  561. $output .= ! is_wp_error( $fields ) ? $fields : '';
  562. $output .= $this->output_conditionals( $connection_id, $connection, $form );
  563. $output .= $this->output_options( $connection_id, $connection );
  564. $output .= '</div>';
  565. return $output;
  566. }
  567. /**
  568. * Connection header HTML.
  569. *
  570. * @since 1.0.0
  571. *
  572. * @param string $connection_id
  573. * @param array $connection
  574. *
  575. * @return string
  576. */
  577. public function output_connection_header( $connection_id = '', $connection = array() ) {
  578. if ( empty( $connection_id ) || empty( $connection ) ) {
  579. return '';
  580. }
  581. $output = '<div class="wpforms-provider-connection-header">';
  582. $output .= sprintf( '<span>%s</span>', sanitize_text_field( $connection['connection_name'] ) );
  583. $output .= '<button class="wpforms-provider-connection-delete"><i class="fa fa-trash-o"></i></button>';
  584. $output .= sprintf( '<input type="hidden" name="providers[%s][%s][connection_name]" value="%s">', $this->slug, $connection_id, esc_attr( $connection['connection_name'] ) );
  585. $output .= '</div>';
  586. return $output;
  587. }
  588. /**
  589. * Provider account authorize fields HTML.
  590. *
  591. * @since 1.0.0
  592. *
  593. * @return mixed
  594. */
  595. public function output_auth() {
  596. }
  597. /**
  598. * Provider account select HTML.
  599. *
  600. * @since 1.0.0
  601. *
  602. * @param string $connection_id Unique connection ID.
  603. * @param array $connection Array of connection data.
  604. *
  605. * @return string
  606. */
  607. public function output_accounts( $connection_id = '', $connection = array() ) {
  608. if ( empty( $connection_id ) || empty( $connection ) ) {
  609. return '';
  610. }
  611. $providers = wpforms_get_providers_options();
  612. if ( empty( $providers[ $this->slug ] ) ) {
  613. return '';
  614. }
  615. $output = '<div class="wpforms-provider-accounts wpforms-connection-block">';
  616. $output .= sprintf( '<h4>%s</h4>', esc_html__( 'Select Account', 'wpforms-lite' ) );
  617. $output .= sprintf( '<select name="providers[%s][%s][account_id]">', $this->slug, $connection_id );
  618. foreach ( $providers[ $this->slug ] as $key => $provider_details ) {
  619. $selected = ! empty( $connection['account_id'] ) ? $connection['account_id'] : '';
  620. $output .= sprintf(
  621. '<option value="%s" %s>%s</option>',
  622. $key,
  623. selected( $selected, $key, false ),
  624. esc_html( $provider_details['label'] )
  625. );
  626. }
  627. $output .= sprintf( '<option value="">%s</a>', esc_html__( 'Add New Account', 'wpforms-lite' ) );
  628. $output .= '</select>';
  629. $output .= '</div>';
  630. return $output;
  631. }
  632. /**
  633. * Provider account lists HTML.
  634. *
  635. * @since 1.0.0
  636. *
  637. * @param string $connection_id
  638. * @param array $connection
  639. *
  640. * @return WP_Error|string
  641. */
  642. public function output_lists( $connection_id = '', $connection = array() ) {
  643. if ( empty( $connection_id ) || empty( $connection['account_id'] ) ) {
  644. return '';
  645. }
  646. $lists = $this->api_lists( $connection_id, $connection['account_id'] );
  647. $selected = ! empty( $connection['list_id'] ) ? $connection['list_id'] : '';
  648. if ( is_wp_error( $lists ) ) {
  649. return $lists;
  650. }
  651. $output = '<div class="wpforms-provider-lists wpforms-connection-block">';
  652. $output .= sprintf( '<h4>%s</h4>', esc_html__( 'Select List', 'wpforms-lite' ) );
  653. $output .= sprintf( '<select name="providers[%s][%s][list_id]">', $this->slug, $connection_id );
  654. if ( ! empty( $lists ) ) {
  655. foreach ( $lists as $list ) {
  656. $output .= sprintf(
  657. '<option value="%s" %s>%s</option>',
  658. esc_attr( $list['id'] ),
  659. selected( $selected, $list['id'], false ),
  660. esc_attr( $list['name'] )
  661. );
  662. }
  663. }
  664. $output .= '</select>';
  665. $output .= '</div>';
  666. return $output;
  667. }
  668. /**
  669. * Provider account list groups HTML.
  670. *
  671. * @since 1.0.0
  672. *
  673. * @param string $connection_id
  674. * @param array $connection
  675. *
  676. * @return string
  677. */
  678. public function output_groups( $connection_id = '', $connection = array() ) {
  679. if ( empty( $connection_id ) || empty( $connection['account_id'] ) || empty( $connection['list_id'] ) ) {
  680. return '';
  681. }
  682. $groupsets = $this->api_groups( $connection_id, $connection['account_id'], $connection['list_id'] );
  683. if ( is_wp_error( $groupsets ) ) {
  684. return '';
  685. }
  686. $output = '<div class="wpforms-provider-groups wpforms-connection-block">';
  687. $output .= sprintf( '<h4>%s</h4>', esc_html__( 'Select Groups', 'wpforms-lite' ) );
  688. $output .= sprintf( '<p>%s</p>', esc_html__( 'We also noticed that you have some segments in your list. You can select specific list segments below if needed. This is optional.', 'wpforms-lite' ) );
  689. $output .= '<div class="wpforms-provider-groups-list">';
  690. foreach ( $groupsets as $groupset ) {
  691. $output .= sprintf( '<p>%s</p>', esc_html( $groupset['name'] ) );
  692. foreach ( $groupset['groups'] as $group ) {
  693. $selected = ! empty( $connection['groups'] ) && ! empty( $connection['groups'][ $groupset['id'] ] ) ? in_array( $group['name'], $connection['groups'][ $groupset['id'] ], true ) : false;
  694. $output .= sprintf(
  695. '<span><input id="group_%s" type="checkbox" value="%s" name="providers[%s][%s][groups][%s][%s]" %s><label for="group_%s">%s</label></span>',
  696. esc_attr( $group['id'] ),
  697. esc_attr( $group['name'] ),
  698. $this->slug,
  699. $connection_id,
  700. $groupset['id'],
  701. $group['id'],
  702. checked( $selected, true, false ),
  703. esc_attr( $group['id'] ),
  704. esc_attr( $group['name'] )
  705. );
  706. }
  707. }
  708. $output .= '</div>';
  709. $output .= '</div>';
  710. return $output;
  711. }
  712. /**
  713. * Provider account list fields HTML.
  714. *
  715. * @since 1.0.0
  716. *
  717. * @param string $connection_id
  718. * @param array $connection
  719. * @param mixed $form
  720. *
  721. * @return WP_Error|string
  722. */
  723. public function output_fields( $connection_id = '', $connection = array(), $form = '' ) {
  724. if ( empty( $connection_id ) || empty( $connection['account_id'] ) || empty( $connection['list_id'] ) || empty( $form ) ) {
  725. return '';
  726. }
  727. $provider_fields = $this->api_fields( $connection_id, $connection['account_id'], $connection['list_id'] );
  728. $form_fields = $this->get_form_fields( $form );
  729. if ( is_wp_error( $provider_fields ) ) {
  730. return $provider_fields;
  731. }
  732. $output = '<div class="wpforms-provider-fields wpforms-connection-block">';
  733. $output .= sprintf( '<h4>%s</h4>', esc_html__( 'List Fields', 'wpforms-lite' ) );
  734. // Table with all the fields.
  735. $output .= '<table>';
  736. $output .= sprintf( '<thead><tr><th>%s</th><th>%s</th></thead>', esc_html__( 'List Fields', 'wpforms-lite' ), esc_html__( 'Available Form Fields', 'wpforms-lite' ) );
  737. $output .= '<tbody>';
  738. foreach ( $provider_fields as $provider_field ) :
  739. $output .= '<tr>';
  740. $output .= '<td>';
  741. $output .= esc_html( $provider_field['name'] );
  742. if (
  743. ! empty( $provider_field['req'] ) &&
  744. (int) $provider_field['req'] === 1
  745. ) {
  746. $output .= '<span class="required">*</span>';
  747. }
  748. $output .= '<td>';
  749. $output .= sprintf( '<select name="providers[%s][%s][fields][%s]">', $this->slug, $connection_id, esc_attr( $provider_field['tag'] ) );
  750. $output .= '<option value=""></option>';
  751. $options = $this->get_form_field_select( $form_fields, $provider_field['field_type'] );
  752. foreach ( $options as $option ) {
  753. $value = sprintf( '%d.%s.%s', $option['id'], $option['key'], $option['provider_type'] );
  754. $selected = ! empty( $connection['fields'][ $provider_field['tag'] ] ) ? selected( $connection['fields'][ $provider_field['tag'] ], $value, false ) : '';
  755. $output .= sprintf( '<option value="%s" %s>%s</option>', esc_attr( $value ), $selected, esc_html( $option['label'] ) );
  756. }
  757. $output .= '</select>';
  758. $output .= '</td>';
  759. $output .= '</tr>';
  760. endforeach;
  761. $output .= '</tbody>';
  762. $output .= '</table>';
  763. $output .= '</div>';
  764. return $output;
  765. }
  766. /**
  767. * Provider connection conditional options HTML.
  768. *
  769. * @since 1.0.0
  770. *
  771. * @param string $connection_id Unique connection ID.
  772. * @param array $connection Configured connection properties.
  773. * @param string|array $form Form properties.
  774. *
  775. * @return string
  776. */
  777. public function output_conditionals( $connection_id = '', $connection = [], $form = '' ) {
  778. if ( empty( $connection['account_id'] ) || ! function_exists( 'wpforms_conditional_logic' ) ) {
  779. return '';
  780. }
  781. return wpforms_conditional_logic()->builder_block(
  782. [
  783. 'form' => $this->form_data,
  784. 'type' => 'panel',
  785. 'panel' => $this->slug,
  786. 'parent' => 'providers',
  787. 'subsection' => $connection_id,
  788. 'reference' => esc_html__( 'Marketing provider connection', 'wpforms-lite' ),
  789. ],
  790. false
  791. );
  792. }
  793. /**
  794. * Provider account list options HTML.
  795. *
  796. * @since 1.0.0
  797. *
  798. * @param string $connection_id
  799. * @param array $connection
  800. *
  801. * @return string
  802. */
  803. public function output_options( $connection_id = '', $connection = array() ) {
  804. }
  805. /********************************************************
  806. * Builder methods - these methods _build_ the Builder. *
  807. ********************************************************/
  808. /**
  809. * Fetch and store the current form data when in the builder.
  810. *
  811. * @since 1.2.3
  812. */
  813. public function builder_form_data() {
  814. if ( ! empty( $_GET['form_id'] ) && empty( $this->form_data ) ) {
  815. $this->form_data = wpforms()->form->get(
  816. absint( $_GET['form_id'] ),
  817. array(
  818. 'content_only' => true,
  819. )
  820. );
  821. }
  822. }
  823. /**
  824. * Display content inside the panel content area.
  825. *
  826. * @since 1.0.0
  827. */
  828. public function builder_content() {
  829. $form_data = $this->form_data;
  830. $providers = wpforms_get_providers_options();
  831. if ( ! empty( $form_data['providers'][ $this->slug ] ) && ! empty( $providers[ $this->slug ] ) ) {
  832. foreach ( $form_data['providers'][ $this->slug ] as $connection_id => $connection ) {
  833. foreach ( $providers[ $this->slug ] as $account_id => $connections ) {
  834. if (
  835. ! empty( $connection['account_id'] ) &&
  836. $connection['account_id'] === $account_id
  837. ) {
  838. echo $this->output_connection( $connection_id, $connection, $form_data );
  839. }
  840. }
  841. }
  842. }
  843. }
  844. /**
  845. * Get provider configured status.
  846. *
  847. * @since 1.6.8
  848. */
  849. private function get_configured() {
  850. return \WPForms\Providers\Provider\Status::init( $this->slug )->is_configured()
  851. ? 'configured'
  852. : '';
  853. }
  854. /**
  855. * Display content inside the panel sidebar area.
  856. *
  857. * @since 1.0.0
  858. */
  859. public function builder_sidebar() {
  860. $configured = $this->get_configured();
  861. echo '<a href="#" class="wpforms-panel-sidebar-section icon ' . esc_attr( $configured ) . ' wpforms-panel-sidebar-section-' . esc_attr( $this->slug ) . '" data-section="' . esc_attr( $this->slug ) . '">';
  862. echo '<img src="' . esc_url( $this->icon ) . '">';
  863. echo esc_html( $this->name );
  864. echo '<i class="fa fa-angle-right wpforms-toggle-arrow"></i>';
  865. if ( ! empty( $configured ) ) {
  866. echo '<i class="fa fa-check-circle-o"></i>';
  867. }
  868. echo '</a>';
  869. }
  870. /**
  871. * Wrap the builder content with the required markup.
  872. *
  873. * @since 1.0.0
  874. */
  875. public function builder_output() {
  876. $form_id = ! empty( $this->form_data['id'] ) ? $this->form_data['id'] : '';
  877. ?>
  878. <div class="wpforms-panel-content-section wpforms-panel-content-section-<?php echo esc_attr( $this->slug ); ?>"
  879. id="<?php echo esc_attr( $this->slug ); ?>-provider">
  880. <?php $this->builder_output_before(); ?>
  881. <div class="wpforms-panel-content-section-title">
  882. <?php echo esc_html( $this->name ); ?>
  883. <button class="wpforms-provider-connections-add" data-form_id="<?php echo absint( $form_id ); ?>"
  884. data-provider="<?php echo esc_attr( $this->slug ); ?>"
  885. data-type="<?php echo esc_attr( strtolower( $this->type ) ); ?>">
  886. <?php
  887. printf( /* translators: %s - Provider type. */
  888. esc_html__( 'Add New %s', 'wpforms-lite' ),
  889. esc_html( $this->type )
  890. );
  891. ?>
  892. </button>
  893. </div>
  894. <?php
  895. FormBuilder::display_content_default_screen(
  896. \WPForms\Providers\Provider\Status::init( $this->slug )->is_connected( $form_id ),
  897. $this->slug,
  898. $this->name,
  899. $this->icon
  900. );
  901. ?>
  902. <div class="wpforms-provider-connections-wrap wpforms-clear">
  903. <div class="wpforms-provider-connections">
  904. <?php $this->builder_content(); ?>
  905. </div>
  906. </div>
  907. <?php $this->builder_output_after(); ?>
  908. </div>
  909. <?php
  910. }
  911. /**
  912. * Optionally output content before the main builder output.
  913. *
  914. * @since 1.3.6
  915. */
  916. public function builder_output_before() {
  917. }
  918. /**
  919. * Optionally output content after the main builder output.
  920. *
  921. * @since 1.3.6
  922. */
  923. public function builder_output_after() {
  924. }
  925. /*************************************************************************
  926. * Integrations tab methods - these methods relate to the settings page. *
  927. *************************************************************************/
  928. /**
  929. * Form fields to add a new provider account.
  930. *
  931. * @since 1.0.0
  932. */
  933. public function integrations_tab_new_form() {
  934. }
  935. /**
  936. * AJAX to disconnect a provider from the settings integrations tab.
  937. *
  938. * @since 1.0.0
  939. */
  940. public function integrations_tab_disconnect() {
  941. // Run a security check.
  942. check_ajax_referer( 'wpforms-admin', 'nonce' );
  943. // Check for permissions.
  944. if ( ! wpforms_current_user_can() ) {
  945. wp_send_json_error(
  946. array(
  947. 'error' => esc_html__( 'You do not have permission', 'wpforms-lite' ),
  948. )
  949. );
  950. }
  951. if ( empty( $_POST['provider'] ) || empty( $_POST['key'] ) ) {
  952. wp_send_json_error(
  953. array(
  954. 'error' => esc_html__( 'Missing data', 'wpforms-lite' ),
  955. )
  956. );
  957. }
  958. $providers = wpforms_get_providers_options();
  959. if ( ! empty( $providers[ $_POST['provider'] ][ $_POST['key'] ] ) ) {
  960. unset( $providers[ $_POST['provider'] ][ $_POST['key'] ] );
  961. update_option( 'wpforms_providers', $providers );
  962. wp_send_json_success();
  963. } else {
  964. wp_send_json_error(
  965. array(
  966. 'error' => esc_html__( 'Connection missing', 'wpforms-lite' ),
  967. )
  968. );
  969. }
  970. }
  971. /**
  972. * AJAX to add a provider from the settings integrations tab.
  973. *
  974. * @since 1.0.0
  975. */
  976. public function integrations_tab_add() {
  977. if ( $_POST['provider'] !== $this->slug ) { //phpcs:ignore
  978. return;
  979. }
  980. // Run a security check.
  981. check_ajax_referer( 'wpforms-admin', 'nonce' );
  982. // Check for permissions.
  983. if ( ! wpforms_current_user_can() ) {
  984. wp_send_json_error(
  985. array(
  986. 'error' => esc_html__( 'You do not have permission', 'wpforms-lite' ),
  987. )
  988. );
  989. }
  990. if ( empty( $_POST['data'] ) ) {
  991. wp_send_json_error(
  992. array(
  993. 'error' => esc_html__( 'Missing data', 'wpforms-lite' ),
  994. )
  995. );
  996. }
  997. $data = wp_parse_args( $_POST['data'], array() );
  998. $auth = $this->api_auth( $data, '' );
  999. if ( is_wp_error( $auth ) ) {
  1000. wp_send_json_error(
  1001. array(
  1002. 'error' => esc_html__( 'Could not connect to the provider.', 'wpforms-lite' ),
  1003. 'error_msg' => $auth->get_error_message(),
  1004. )
  1005. );
  1006. } else {
  1007. $account = '<li class="wpforms-clear">';
  1008. $account .= '<span class="label">' . sanitize_text_field( $data['label'] ) . '</span>';
  1009. /* translators: %s - Connection date. */
  1010. $account .= '<span class="date">' . sprintf( esc_html__( 'Connected on: %s', 'wpforms-lite' ), date_i18n( get_option( 'date_format', time() ) ) ) . '</span>';
  1011. $account .= '<span class="remove"><a href="#" data-provider="' . $this->slug . '" data-key="' . esc_attr( $auth ) . '">' . esc_html__( 'Disconnect', 'wpforms-lite' ) . '</a></span>';
  1012. $account .= '</li>';
  1013. wp_send_json_success(
  1014. array(
  1015. 'html' => $account,
  1016. )
  1017. );
  1018. }
  1019. }
  1020. /**
  1021. * Add provider to the Settings Integrations tab.
  1022. *
  1023. * @since 1.0.0
  1024. *
  1025. * @param array $active Array of active connections.
  1026. * @param array $settings Array of all connections settings.
  1027. */
  1028. public function integrations_tab_options( $active, $settings ) {
  1029. $connected = ! empty( $active[ $this->slug ] );
  1030. $accounts = ! empty( $settings[ $this->slug ] ) ? $settings[ $this->slug ] : array();
  1031. $class = $connected && $accounts ? 'connected' : '';
  1032. $arrow = 'right';
  1033. /* translators: %s - provider name. */
  1034. $title_connect_to = sprintf( esc_html__( 'Connect to %s', 'wpforms-lite' ), esc_html( $this->name ) );
  1035. // This lets us highlight a specific service by a special link.
  1036. if ( ! empty( $_GET['wpforms-integration'] ) ) { //phpcs:ignore
  1037. if ( $this->slug === $_GET['wpforms-integration'] ) { //phpcs:ignore
  1038. $class .= ' focus-in';
  1039. $arrow = 'down';
  1040. } else {
  1041. $class .= ' focus-out';
  1042. }
  1043. }
  1044. ?>
  1045. <div id="wpforms-integration-<?php echo esc_attr( $this->slug ); ?>" class="wpforms-settings-provider wpforms-clear <?php echo esc_attr( $this->slug ); ?> <?php echo esc_attr( $class ); ?>">
  1046. <div class="wpforms-settings-provider-header wpforms-clear" data-provider="<?php echo esc_attr( $this->slug ); ?>">
  1047. <div class="wpforms-settings-provider-logo">
  1048. <i title="<?php esc_attr_e( 'Show Accounts', 'wpforms-lite' ); ?>" class="fa fa-chevron-<?php echo esc_attr( $arrow ); ?>"></i>
  1049. <img src="<?php echo esc_url( $this->icon ); ?>">
  1050. </div>
  1051. <div class="wpforms-settings-provider-info">
  1052. <h3><?php echo esc_html( $this->name ); ?></h3>
  1053. <p>
  1054. <?php
  1055. /* translators: %s - provider name. */
  1056. printf( esc_html__( 'Integrate %s with WPForms', 'wpforms-lite' ), esc_html( $this->name ) );
  1057. ?>
  1058. </p>
  1059. <span class="connected-indicator green"><i class="fa fa-check-circle-o"></i>&nbsp;<?php esc_html_e( 'Connected', 'wpforms-lite' ); ?></span>
  1060. </div>
  1061. </div>
  1062. <div class="wpforms-settings-provider-accounts" id="provider-<?php echo esc_attr( $this->slug ); ?>">
  1063. <div class="wpforms-settings-provider-accounts-list">
  1064. <ul>
  1065. <?php
  1066. if ( ! empty( $accounts ) ) {
  1067. foreach ( $accounts as $key => $account ) {
  1068. echo '<li class="wpforms-clear">';
  1069. echo '<span class="label">' . esc_html( $account['label'] ) . '</span>';
  1070. /* translators: %s - Connection date. */
  1071. echo '<span class="date">' . sprintf( esc_html__( 'Connected on: %s', 'wpforms-lite' ), date_i18n( get_option( 'date_format' ), intval( $account['date'] ) ) ) . '</span>';
  1072. echo '<span class="remove"><a href="#" data-provider="' . esc_attr( $this->slug ) . '" data-key="' . esc_attr( $key ) . '">' . esc_html__( 'Disconnect', 'wpforms-lite' ) . '</a></span>';
  1073. echo '</li>';
  1074. }
  1075. }
  1076. ?>
  1077. </ul>
  1078. </div>
  1079. <p class="wpforms-settings-provider-accounts-toggle">
  1080. <a class="wpforms-btn wpforms-btn-md wpforms-btn-light-grey" href="#" data-provider="<?php echo esc_attr( $this->slug ); ?>">
  1081. <i class="fa fa-plus"></i> <?php esc_html_e( 'Add New Account', 'wpforms-lite' ); ?>
  1082. </a>
  1083. </p>
  1084. <div class="wpforms-settings-provider-accounts-connect">
  1085. <form>
  1086. <p><?php esc_html_e( 'Please fill out all of the fields below to add your new provider account.', 'wpforms-lite' ); ?></span></p>
  1087. <p class="wpforms-settings-provider-accounts-connect-fields">
  1088. <?php $this->integrations_tab_new_form(); ?>
  1089. </p>
  1090. <button type="submit" class="wpforms-btn wpforms-btn-md wpforms-btn-orange wpforms-settings-provider-connect"
  1091. data-provider="<?php echo esc_attr( $this->slug ); ?>" title="<?php echo esc_attr( $title_connect_to ); ?>">
  1092. <?php echo esc_html( $title_connect_to ); ?>
  1093. </button>
  1094. </form>
  1095. </div>
  1096. </div>
  1097. </div>
  1098. <?php
  1099. }
  1100. /**
  1101. * Error wrapper for WP_Error.
  1102. *
  1103. * @since 1.0.0
  1104. *
  1105. * @param string $message
  1106. * @param string $parent
  1107. *
  1108. * @return WP_Error
  1109. */
  1110. public function error( $message = '', $parent = '0' ) {
  1111. return new WP_Error( $this->slug . '-error', $message );
  1112. }
  1113. }