settings-api.php 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. <?php
  2. /**
  3. * Settings API for the Tracking Tab
  4. *
  5. * @since 6.0.0
  6. *
  7. * @package MonsterInsights
  8. * @subpackage Settings API
  9. * @author Chris Christoff
  10. */
  11. // Exit if accessed directly
  12. if ( !defined( 'ABSPATH' ) ) exit;
  13. /**
  14. * Get the settings for a section
  15. *
  16. * @since 6.0.0
  17. * @return void
  18. */
  19. function monsterinsights_get_section_settings( $section, $page = 'tracking' ) {
  20. $output = '';
  21. $settings = monsterinsights_get_registered_settings();
  22. if ( is_array( $settings ) && ! empty( $settings[$section] ) && is_array( $settings[$section] ) ) {
  23. foreach ( $settings[$section] as $setting ) {
  24. $args = wp_parse_args( $setting, array(
  25. 'id' => null,
  26. 'desc' => '',
  27. 'name' => '',
  28. 'size' => null,
  29. 'options' => '',
  30. 'std' => '',
  31. 'min' => null,
  32. 'max' => null,
  33. 'step' => null,
  34. 'select2' => null,
  35. 'placeholder' => null,
  36. 'allow_blank' => true,
  37. 'readonly' => false,
  38. 'faux' => false,
  39. 'tooltip_title' => false,
  40. 'tooltip_desc' => false,
  41. 'field_class' => '',
  42. 'multiple' => false,
  43. 'allowclear' => true,
  44. 'notice_type' => 'info',
  45. 'no_label' => false,
  46. ) );
  47. $output .= monsterinsights_render_field( $args );
  48. }
  49. }
  50. return $output;
  51. }
  52. /**
  53. * Saves Settings
  54. *
  55. * @since 6.0.0
  56. * @access public
  57. *
  58. * @return null Return early if not fixing the broken migration
  59. */
  60. function monsterinsights_save_settings() {
  61. // Check if user pressed the 'Update' button and nonce is valid
  62. if ( ! isset( $_POST['monsterinsights-settings-submit'] ) ) {
  63. return;
  64. }
  65. if ( ! wp_verify_nonce( $_POST['monsterinsights-settings-nonce'], 'monsterinsights-settings-nonce' ) ) {
  66. return;
  67. }
  68. if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
  69. return;
  70. }
  71. if ( empty( $_POST['monsterinsights_settings_tab'] ) || empty( $_POST['monsterinsights_settings_sub_tab'] ) || $_POST['monsterinsights_settings_tab'] !== 'tracking' ) {
  72. return;
  73. }
  74. // get subtab
  75. $settings = monsterinsights_get_registered_settings();
  76. $tab = $_POST['monsterinsights_settings_sub_tab'];
  77. if ( empty( $settings ) || !is_array( $settings ) || empty( $settings[ $tab ] ) || ! is_array( $settings[ $tab ] ) ) {
  78. return;
  79. }
  80. // Okay we're good to sanitize, validate, and save this section's settings
  81. // We only care about this sections's settings
  82. $settings = $settings[ $tab ];
  83. // Run a general sanitization for the tab for special fields
  84. $input = ! empty( $_POST['monsterinsights_settings'] ) ? $_POST['monsterinsights_settings'] : array();
  85. $input = apply_filters( 'monsterinsights_settings_' . $tab . '_sanitize', $input );
  86. foreach( $settings as $id => $setting ) {
  87. // If the value wasn't passed in, set to false, which will delete the option
  88. $value = isset( $input[ $id ] ) ? $input[ $id ] : false;
  89. $previous_value = monsterinsights_get_option( $id, false );
  90. // Sanitize/Validate
  91. if ( empty( $setting['type'] ) ) {
  92. continue;
  93. }
  94. // Some setting types are not actually settings, just keep moving along here
  95. $non_setting_types = monsterinsights_get_non_setting_types();
  96. $type = $setting['type'];
  97. if ( in_array( $type, $non_setting_types ) ) {
  98. continue;
  99. }
  100. $args = wp_parse_args( $setting, array(
  101. 'id' => null,
  102. 'desc' => '',
  103. 'name' => '',
  104. 'size' => null,
  105. 'options' => '',
  106. 'std' => '',
  107. 'min' => null,
  108. 'max' => null,
  109. 'step' => null,
  110. 'select2' => null,
  111. 'placeholder' => null,
  112. 'allow_blank' => true,
  113. 'readonly' => false,
  114. 'faux' => false,
  115. 'tooltip_title' => false,
  116. 'tooltip_desc' => false,
  117. 'field_class' => '',
  118. 'multiple' => false,
  119. 'allowclear' => true,
  120. 'notice_type' => 'info',
  121. ) );
  122. // Sanitize settings
  123. $value = apply_filters( 'monsterinsights_settings_sanitize_' . $id , $value, $id, $args, $previous_value );
  124. $value = apply_filters( 'monsterinsights_settings_sanitize_' . $type, $value, $id, $args, $previous_value );
  125. $value = apply_filters( 'monsterinsights_settings_sanitize' , $value, $id, $args, $previous_value );
  126. // Save
  127. if ( ! has_action( 'monsterinsights_settings_save_' . $args['type'] ) ) {
  128. monsterinsights_update_option( $id, $value );
  129. } else {
  130. do_action( 'monsterinsights_settings_save_' . $args['type'], $value, $id, $args, $previous_value );
  131. }
  132. }
  133. add_action( 'monsterinsights_tracking_' . $tab . '_tab_notice', 'monsterinsights_updated_settings' );
  134. }
  135. add_action( 'current_screen', 'monsterinsights_save_settings' );
  136. function monsterinsights_is_settings_tab( $tab = '' ){
  137. $tabs = monsterinsights_get_settings_tabs();
  138. if ( empty( $tab ) || empty( $tabs ) || ! is_string( $tab ) || ! is_array( $tabs ) ) {
  139. return false;
  140. }
  141. return !empty( $tabs[$tab]);
  142. }
  143. /**
  144. * Flattens the set of registered settings and their type so we can easily sanitize all the settings
  145. * in a much cleaner set of logic in monsterinsights_settings_sanitize
  146. *
  147. * @since 6.0.0
  148. * @return array Key is the setting ID, value is the type of setting it is registered as
  149. */
  150. function monsterinsights_get_registered_settings_types( $section = '' ) {
  151. $settings = monsterinsights_get_registered_settings();
  152. $setting_types = array();
  153. if ( ! empty( $section ) ) {
  154. if ( ! empty( $settings[$section] ) ) {
  155. foreach ( $settings[$section] as $setting ) {
  156. if ( is_array( $setting ) && array_key_exists( 'type', $setting ) ) {
  157. $setting_types[ $setting['id'] ] = $setting['type'];
  158. }
  159. }
  160. }
  161. } else {
  162. foreach ( $settings as $tab ) {
  163. foreach ( $tab as $setting ) {
  164. if ( is_array( $setting ) && array_key_exists( 'type', $setting ) ) {
  165. $setting_types[ $setting['id'] ] = $setting['type'];
  166. }
  167. }
  168. }
  169. }
  170. return $setting_types;
  171. }
  172. /**
  173. * Sanitize rich editor fields
  174. *
  175. * @since 6.0.0
  176. * @param array $input The field value
  177. * @return string $input Sanitizied value
  178. */
  179. function monsterinsights_sanitize_rich_editor_field( $input ) {
  180. $tags = array(
  181. 'p' => array(
  182. 'class' => array(),
  183. 'id' => array(),
  184. ),
  185. 'span' => array(
  186. 'class' => array(),
  187. 'id' => array(),
  188. ),
  189. 'a' => array(
  190. 'href' => array(),
  191. 'title' => array(),
  192. 'class' => array(),
  193. 'title' => array(),
  194. 'id' => array(),
  195. ),
  196. 'strong' => array(),
  197. 'em' => array(),
  198. 'br' => array(),
  199. 'img' => array(
  200. 'src' => array(),
  201. 'title' => array(),
  202. 'alt' => array(),
  203. 'id' => array(),
  204. ),
  205. 'div' => array(
  206. 'class' => array(),
  207. 'id' => array(),
  208. ),
  209. 'ul' => array(
  210. 'class' => array(),
  211. 'id' => array(),
  212. ),
  213. 'li' => array(
  214. 'class' => array(),
  215. 'id' => array(),
  216. )
  217. );
  218. //$allowed_tags = apply_filters( 'monsterinsights_allowed_html_tags', $tags );
  219. return trim( wp_kses( $input, $allowed_tags ) );
  220. }
  221. add_filter( 'monsterinsights_settings_sanitize_rich_editor', 'monsterinsights_sanitize_rich_editor_field' );
  222. if ( ! function_exists( 'sanitize_textarea_field' ) ) {
  223. function sanitize_textarea_field( $str ) {
  224. $filtered = _sanitize_text_fields( $str, true );
  225. return apply_filters( 'sanitize_textarea_field', $filtered, $str );
  226. }
  227. }
  228. if ( ! function_exists( 'sanitize_textarea_field' ) ) {
  229. function _sanitize_text_fields( $str, $keep_newlines = false ) {
  230. $filtered = wp_check_invalid_utf8( $str );
  231. if ( strpos($filtered, '<') !== false ) {
  232. $filtered = wp_pre_kses_less_than( $filtered );
  233. // This will strip extra whitespace for us.
  234. $filtered = wp_strip_all_tags( $filtered, false );
  235. // Use html entities in a special case to make sure no later
  236. // newline stripping stage could lead to a functional tag
  237. $filtered = str_replace("<\n", "&lt;\n", $filtered);
  238. }
  239. if ( ! $keep_newlines ) {
  240. $filtered = preg_replace( '/[\r\n\t ]+/', ' ', $filtered );
  241. }
  242. $filtered = trim( $filtered );
  243. $found = false;
  244. while ( preg_match('/%[a-f0-9]{2}/i', $filtered, $match) ) {
  245. $filtered = str_replace($match[0], '', $filtered);
  246. $found = true;
  247. }
  248. if ( $found ) {
  249. // Strip out the whitespace that may now exist after removing the octets.
  250. $filtered = trim( preg_replace('/ +/', ' ', $filtered) );
  251. }
  252. return $filtered;
  253. }
  254. }
  255. /**
  256. * Sanitize textarea fields
  257. *
  258. * @since 6.0.0
  259. * @todo docbloc
  260. */
  261. function monsterinsights_sanitize_textarea_field( $value, $id, $setting, $previous_value ) {
  262. return sanitize_textarea_field( $value );
  263. }
  264. add_filter( 'monsterinsights_settings_sanitize_textarea', 'monsterinsights_sanitize_textarea_field', 10, 4 );
  265. /**
  266. * Sanitize checkbox fields
  267. *
  268. * @since 6.0.0
  269. * @todo docbloc
  270. */
  271. function monsterinsights_sanitize_checkbox_field( $value, $id, $setting, $previous_value ) {
  272. return (bool) $value;
  273. }
  274. add_filter( 'monsterinsights_settings_sanitize_checkbox', 'monsterinsights_sanitize_checkbox_field', 10, 4 );
  275. /**
  276. * Sanitize multicheck fields
  277. *
  278. * @since 6.0.0
  279. * @todo docbloc
  280. */
  281. function monsterinsights_sanitize_multicheck_field( $value, $id, $setting, $previous_value ) {
  282. $save_value = array();
  283. if ( ! empty( $value ) && is_array( $value ) ) {
  284. foreach( $setting['options'] as $key => $option ){
  285. if ( in_array( $key, $value ) ) {
  286. $save_value[] = $key;
  287. }
  288. }
  289. }
  290. return $save_value;
  291. }
  292. add_filter( 'monsterinsights_settings_sanitize_multicheck', 'monsterinsights_sanitize_multicheck_field', 10, 4 );
  293. /**
  294. * Sanitize select fields
  295. *
  296. * @since 6.0.0
  297. * @todo docbloc
  298. */
  299. function monsterinsights_sanitize_select_field( $value, $id, $setting, $previous_value ) {
  300. if ( ! empty( $setting['multiple'] ) && $setting['multiple'] ) {
  301. $save_value = array();
  302. } else {
  303. $save_value = '';
  304. }
  305. if ( ! empty( $value ) && is_array( $value ) ) {
  306. if ( $setting['multiple'] ) {
  307. foreach ( $value as $vid => $vname ) {
  308. foreach( $setting['options'] as $key => $option ){
  309. if ( $key === $vname ) {
  310. $save_value[] = $key;
  311. break;
  312. }
  313. }
  314. }
  315. } else {
  316. foreach( $setting['options'] as $key => $option ){
  317. if ( is_array( $value ) && in_array( $key, $value ) ) {
  318. $save_value = $key;
  319. break;
  320. } else if ( is_string( $value ) && $key === $value ){
  321. $save_value = $key;
  322. break;
  323. }
  324. }
  325. }
  326. }
  327. return $save_value;
  328. }
  329. add_filter( 'monsterinsights_settings_sanitize_select', 'monsterinsights_sanitize_select_field', 10, 4 );
  330. /**
  331. * Sanitize radio fields
  332. *
  333. * @since 6.0.0
  334. * @todo docbloc
  335. */
  336. function monsterinsights_sanitize_radio_field( $value, $id, $setting, $previous_value ) {
  337. $save_value = '';
  338. if ( ! empty( $value ) ) {
  339. foreach( $setting['options'] as $key => $option ){
  340. if ( $key === $value ) {
  341. $save_value = $key;
  342. }
  343. }
  344. }
  345. return $save_value;
  346. }
  347. add_filter( 'monsterinsights_settings_sanitize_radio', 'monsterinsights_sanitize_radio_field', 10, 4 );
  348. /**
  349. * Sanitize text fields
  350. *
  351. * @since 6.0.0
  352. * @todo docbloc
  353. */
  354. function monsterinsights_sanitize_text_field( $value, $id, $setting, $previous_value ) {
  355. return sanitize_text_field( $value );
  356. }
  357. add_filter( 'monsterinsights_settings_sanitize_text', 'monsterinsights_sanitize_text_field', 10, 4 );
  358. /**
  359. * Sanitize password fields
  360. *
  361. * @since 6.0.0
  362. * @todo docbloc
  363. */
  364. function monsterinsights_sanitize_password_field( $value, $id, $setting, $previous_value ) {
  365. return sanitize_text_field( $value );
  366. }
  367. add_filter( 'monsterinsights_settings_sanitize_password', 'monsterinsights_sanitize_password_field', 10, 4 );
  368. /**
  369. * Sanitize number fields
  370. *
  371. * @since 6.0.0
  372. * @todo docbloc
  373. */
  374. function monsterinsights_sanitize_number_field( $value, $id, $setting, $previous_value ) {
  375. if ( is_int( (int) $value ) ) {
  376. return $value;
  377. } else if ( is_int( $previous_value ) ) {
  378. return $previous_value;
  379. } else {
  380. return 0;
  381. }
  382. }
  383. add_filter( 'monsterinsights_settings_sanitize_number', 'monsterinsights_sanitize_number_field', 10, 4 );
  384. /**
  385. * Sanitize unfiltered textarea fields
  386. *
  387. * @since 6.0.0
  388. * @todo docbloc
  389. */
  390. function monsterinsights_sanitize_unfiltered_textarea_field( $value, $id, $setting, $previous_value ) {
  391. if ( current_user_can( 'unfiltered_html' ) || current_user_can( 'monsterinsights_unfiltered_html' ) ) {
  392. return $value;
  393. } else {
  394. return $previous_value;
  395. }
  396. }
  397. add_filter( 'monsterinsights_settings_unfiltered_textarea_number', 'monsterinsights_sanitize_unfiltered_textarea_field', 10, 4 );
  398. /**
  399. * Sanitizes a string key for MonsterInsights Settings
  400. *
  401. * Keys are used as internal identifiers. Alphanumeric characters, dashes, underscores, stops, colons and slashes are allowed
  402. *
  403. * @since 6.0.0
  404. * @param string $key String key
  405. * @return string Sanitized key
  406. */
  407. function monsterinsights_sanitize_key( $key ) {
  408. $raw_key = $key;
  409. $key = preg_replace( '/[^a-zA-Z0-9_\-\.\:\/]/', '', $key );
  410. /**
  411. * Filter a sanitized key string.
  412. *
  413. * @since 6.0.0
  414. * @param string $key Sanitized key.
  415. * @param string $raw_key The key prior to sanitization.
  416. */
  417. return apply_filters( 'monsterinsights_sanitize_key', $key, $raw_key );
  418. }
  419. /**
  420. * Sanitize HTML Class Names
  421. *
  422. * @since 6.0.0
  423. * @param string|array $class HTML Class Name(s)
  424. * @return string $class
  425. */
  426. function monsterinsights_sanitize_html_class( $class = '' ) {
  427. if ( is_string( $class ) ) {
  428. $class = sanitize_html_class( $class );
  429. } else if ( is_array( $class ) ) {
  430. $class = array_values( array_map( 'sanitize_html_class', $class ) );
  431. $class = implode( ' ', array_unique( $class ) );
  432. }
  433. return $class;
  434. }
  435. /**
  436. * Retrieve a list of all published pages
  437. *
  438. * On large sites this can be expensive, so only load if on the settings page or $force is set to true
  439. *
  440. * @since 6.0.0
  441. * @param bool $force Force the pages to be loaded even if not on settings
  442. * @return array $pages_options An array of the pages
  443. */
  444. function monsterinsights_get_pages( $force = false ) {
  445. $pages_options = array( '' => '' ); // Blank option
  446. if( ( ! isset( $_GET['page'] ) || 'monsterinsights_settings' != $_GET['page'] ) && ! $force ) {
  447. return $pages_options;
  448. }
  449. $pages = get_pages();
  450. if ( $pages ) {
  451. foreach ( $pages as $page ) {
  452. $pages_options[ $page->ID ] = $page->post_title;
  453. }
  454. }
  455. return $pages_options;
  456. }
  457. /**
  458. * Checkbox Callback
  459. *
  460. * Renders checkboxes.
  461. *
  462. * @since 6.0.0
  463. * @param array $args Arguments passed by the setting
  464. *
  465. * @return void
  466. */
  467. function monsterinsights_checkbox_callback( $args ) {
  468. $monsterinsights_option = monsterinsights_get_option( $args['id'] );
  469. if ( isset( $args['faux'] ) && true === $args['faux'] ) {
  470. $name = '';
  471. } else {
  472. $name = 'name="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . ']"';
  473. }
  474. $class = monsterinsights_sanitize_html_class( $args['field_class'] );
  475. $checked = ! empty( $monsterinsights_option ) ? checked( 1, $monsterinsights_option, false ) : '';
  476. $disabled = '';
  477. if ( isset( $args['faux'] ) && true === $args['faux'] ) {
  478. // Disable class
  479. $disabled = 'disabled="disabled"';
  480. // Checked
  481. $checked = isset( $args['std'] ) && true === $args['std'] ? checked( 1, 1, false ) : '';
  482. }
  483. $html = '<input type="checkbox" id="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . ']"' . $name . ' value="1" ' . $checked . ' class="' . $class . '" ' . $disabled . ' />';
  484. $html .= '<p class="description">' . wp_kses_post( $args['desc'] ) . '</p>';
  485. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  486. }
  487. /**
  488. * Multicheck Callback
  489. *
  490. * Renders multiple checkboxes.
  491. *
  492. * @since 6.0.0
  493. * @param array $args Arguments passed by the setting
  494. *
  495. * @return void
  496. */
  497. function monsterinsights_multicheck_callback( $args ) {
  498. $monsterinsights_option = monsterinsights_get_option( $args['id'] );
  499. $class = monsterinsights_sanitize_html_class( $args['field_class'] );
  500. $html = '';
  501. if ( ! empty( $args['options'] ) ) {
  502. foreach( $args['options'] as $key => $option ):
  503. if( isset( $monsterinsights_option[ $key ] ) ) { $enabled = $option; } else { $enabled = NULL; }
  504. $html .= '<input name="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . '][' . monsterinsights_sanitize_key( $key ) . ']" id="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . '][' . monsterinsights_sanitize_key( $key ) . ']" class="' . $class . '" type="checkbox" value="' . esc_attr( $option ) . '" ' . checked($option, $enabled, false) . '/>&nbsp;';
  505. $html .= '<label for="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . '][' . monsterinsights_sanitize_key( $key ) . ']">' . wp_kses_post( $option ) . '</label><br/>';
  506. endforeach;
  507. $html .= '<p class="description">' . $args['desc'] . '</p>';
  508. }
  509. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  510. }
  511. /**
  512. * Radio Callback
  513. *
  514. * Renders radio boxes.
  515. *
  516. * @since 6.0.0
  517. * @param array $args Arguments passed by the setting
  518. *
  519. * @return void
  520. */
  521. function monsterinsights_radio_callback( $args ) {
  522. $monsterinsights_options = monsterinsights_get_option( $args['id'] );
  523. $html = '';
  524. $class = monsterinsights_sanitize_html_class( $args['field_class'] );
  525. foreach ( $args['options'] as $key => $option ) :
  526. $checked = false;
  527. if ( $monsterinsights_options && $monsterinsights_options == $key ) {
  528. $checked = true;
  529. } else if( isset( $args['std'] ) && $args['std'] == $key && ! $monsterinsights_options ) {
  530. $checked = true;
  531. }
  532. $html .= '<label for="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . '][' . monsterinsights_sanitize_key( $key ) . ']">';
  533. $html .= '<input name="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . ']" id="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . '][' . monsterinsights_sanitize_key( $key ) . ']" class="' . $class . '" type="radio" value="' . monsterinsights_sanitize_key( $key ) . '" ' . checked(true, $checked, false) . '/>&nbsp;';
  534. $html .= esc_html( $option ) . '</label>';
  535. endforeach;
  536. $html .= '<p class="description">' . apply_filters( 'monsterinsights_after_setting_output', wp_kses_post( $args['desc'] ), $args ) . '</p>';
  537. return $html;
  538. }
  539. /**
  540. * Text Callback
  541. *
  542. * Renders text fields.
  543. *
  544. * @since 6.0.0
  545. * @param array $args Arguments passed by the setting
  546. *
  547. * @return void
  548. */
  549. function monsterinsights_text_callback( $args ) {
  550. $monsterinsights_option = monsterinsights_get_option( $args['id'] );
  551. if ( $monsterinsights_option ) {
  552. $value = $monsterinsights_option;
  553. } elseif( ! empty( $args['allow_blank'] ) && empty( $monsterinsights_option ) ) {
  554. $value = '';
  555. } else {
  556. $value = isset( $args['std'] ) ? $args['std'] : '';
  557. }
  558. if ( isset( $args['faux'] ) && true === $args['faux'] ) {
  559. $args['readonly'] = true;
  560. $value = isset( $args['std'] ) ? $args['std'] : '';
  561. $name = '';
  562. } else {
  563. $name = 'name="monsterinsights_settings[' . esc_attr( $args['id'] ) . ']"';
  564. }
  565. $class = monsterinsights_sanitize_html_class( $args['field_class'] );
  566. $disabled = ! empty( $args['disabled'] ) ? ' disabled="disabled"' : '';
  567. $readonly = $args['readonly'] === true ? ' readonly="readonly"' : '';
  568. $size = ( isset( $args['size'] ) && ! is_null( $args['size'] ) ) ? $args['size'] : 'regular';
  569. $html = '<input type="text" class="' . $class . ' ' . sanitize_html_class( $size ) . '-text" id="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . ']" ' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . $disabled . ' placeholder="' . esc_attr( $args['placeholder'] ) . '"/>';
  570. $html .= '<p class="description"> ' . wp_kses_post( $args['desc'] ) . '</p>';
  571. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  572. }
  573. /**
  574. * Number Callback
  575. *
  576. * Renders number fields.
  577. *
  578. * @since 6.0.0
  579. * @param array $args Arguments passed by the setting
  580. *
  581. * @return void
  582. */
  583. function monsterinsights_number_callback( $args ) {
  584. $monsterinsights_option = monsterinsights_get_option( $args['id'] );
  585. if ( $monsterinsights_option ) {
  586. $value = $monsterinsights_option;
  587. } else {
  588. $value = isset( $args['std'] ) ? $args['std'] : '';
  589. }
  590. if ( isset( $args['faux'] ) && true === $args['faux'] ) {
  591. $args['readonly'] = true;
  592. $value = isset( $args['std'] ) ? $args['std'] : '';
  593. $name = '';
  594. } else {
  595. $name = 'name="monsterinsights_settings[' . esc_attr( $args['id'] ) . ']"';
  596. }
  597. $class = monsterinsights_sanitize_html_class( $args['field_class'] );
  598. $max = isset( $args['max'] ) ? $args['max'] : 999999;
  599. $min = isset( $args['min'] ) ? $args['min'] : 0;
  600. $step = isset( $args['step'] ) ? $args['step'] : 1;
  601. $size = ( isset( $args['size'] ) && ! is_null( $args['size'] ) ) ? $args['size'] : 'regular';
  602. $html = '<input type="number" step="' . esc_attr( $step ) . '" max="' . esc_attr( $max ) . '" min="' . esc_attr( $min ) . '" class="' . $class . ' ' . sanitize_html_class( $size ) . '-text" id="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . ']" ' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"/>';
  603. $html .= '<p class="description"> ' . wp_kses_post( $args['desc'] ) . '</p>';
  604. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  605. }
  606. /**
  607. * Textarea Callback
  608. *
  609. * Renders textarea fields.
  610. *
  611. * @since 6.0.0
  612. * @param array $args Arguments passed by the setting
  613. *
  614. * @return void
  615. */
  616. function monsterinsights_textarea_callback( $args ) {
  617. $monsterinsights_option = monsterinsights_get_option( $args['id'] );
  618. if ( $monsterinsights_option ) {
  619. $value = $monsterinsights_option;
  620. } else {
  621. $value = isset( $args['std'] ) ? $args['std'] : '';
  622. }
  623. $class = monsterinsights_sanitize_html_class( $args['field_class'] );
  624. $html = '<textarea class="' . $class . ' large-text" cols="50" rows="5" id="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . ']" name="monsterinsights_settings[' . esc_attr( $args['id'] ) . ']">' . esc_textarea( stripslashes( $value ) ) . '</textarea>';
  625. $html .= '<p class="description"> ' . wp_kses_post( $args['desc'] ) . '</p>';
  626. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  627. }
  628. /**
  629. * Unfiltered Textarea Callback
  630. *
  631. * Renders unfiltered textarea fields.
  632. *
  633. * @since 6.0.0
  634. * @param array $args Arguments passed by the setting
  635. *
  636. * @return void
  637. */
  638. function monsterinsights_unfiltered_textarea_callback( $args ) {
  639. if ( current_user_can( 'unfiltered_html' ) || current_user_can( 'monsterinsights_unfiltered_html' ) ) {
  640. $monsterinsights_option = monsterinsights_get_option( $args['id'] );
  641. if ( $monsterinsights_option ) {
  642. $value = $monsterinsights_option;
  643. } else {
  644. $value = isset( $args['std'] ) ? $args['std'] : '';
  645. }
  646. $class = monsterinsights_sanitize_html_class( $args['field_class'] );
  647. $html = '<textarea class="' . $class . ' large-text" cols="50" rows="5" id="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . ']" name="monsterinsights_settings[' . esc_attr( $args['id'] ) . ']">' . stripslashes( $value ) . '</textarea>';
  648. $html .= '<p class="description"> ' . wp_kses_post( $args['desc'] ) . '</p>';
  649. } else {
  650. $html .= sprintf( esc_html__( 'You must have the %s capability to view/edit this setting', 'google-analytics-for-wordpress' ), '"unfiltered_html"' );
  651. }
  652. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  653. }
  654. /**
  655. * Password Callback
  656. *
  657. * Renders password fields.
  658. *
  659. * @since 6.0.0
  660. * @param array $args Arguments passed by the setting
  661. *
  662. * @return void
  663. */
  664. function monsterinsights_password_callback( $args ) {
  665. $monsterinsights_options = monsterinsights_get_option( $args['id'] );
  666. if ( $monsterinsights_options ) {
  667. $value = $monsterinsights_options;
  668. } else {
  669. $value = isset( $args['std'] ) ? $args['std'] : '';
  670. }
  671. $class = monsterinsights_sanitize_html_class( $args['field_class'] );
  672. $size = ( isset( $args['size'] ) && ! is_null( $args['size'] ) ) ? $args['size'] : 'regular';
  673. $html = '<input type="password" class="' . $class . ' ' . sanitize_html_class( $size ) . '-text" id="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . ']" name="monsterinsights_settings[' . esc_attr( $args['id'] ) . ']" value="' . esc_attr( $value ) . '"/>';
  674. $html .= '<p class="description"> ' . wp_kses_post( $args['desc'] ) . '</p>';
  675. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  676. }
  677. /**
  678. * Select Callback
  679. *
  680. * Renders select fields.
  681. *
  682. * @since 6.0.0
  683. * @param array $args Arguments passed by the setting
  684. *
  685. * @return void
  686. */
  687. function monsterinsights_select_callback($args) {
  688. $monsterinsights_option = monsterinsights_get_option( $args['id'] );
  689. if ( $monsterinsights_option ) {
  690. $value = $monsterinsights_option;
  691. } else {
  692. $value = isset( $args['std'] ) ? $args['std'] : '';
  693. }
  694. if ( isset( $args['placeholder'] ) ) {
  695. $placeholder = $args['placeholder'];
  696. } else {
  697. $placeholder = '';
  698. }
  699. $class = monsterinsights_sanitize_html_class( $args['field_class'] );
  700. if ( isset( $args['select2'] ) ) {
  701. $class .= ' monsterinsights-select300';
  702. }
  703. $allowclear = isset( $args['allowclear'] ) ? (bool) $args['allowclear'] : false;
  704. $multiple = isset( $args['multiple'] ) ? (bool) $args['multiple'] : false;
  705. $multiple = $multiple ? 'multiple="multiple"' : '';
  706. $multiple_arg = $multiple ? '[]' : '';
  707. $html = '<select id="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . ']" name="monsterinsights_settings[' . esc_attr( $args['id'] ) . ']' . $multiple_arg .'" class="' . $class . '" data-placeholder="' . esc_html( $placeholder ) . '" data-allow-clear="' . $allowclear . '" ' . $multiple . ' />';
  708. foreach ( $args['options'] as $option => $name ) {
  709. $selected = ! empty( $value ) && is_array( $value ) ? in_array( $option, $value ) : $value === $option;
  710. $selected = selected( true, $selected, false );
  711. $html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( $name ) . '</option>';
  712. }
  713. $html .= '</select>';
  714. $html .= '<p class="description"> ' . wp_kses_post( $args['desc'] ) . '</p>';
  715. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  716. }
  717. /**
  718. * Rich Editor Callback
  719. *
  720. * Renders rich editor fields.
  721. *
  722. * @since 6.0.0
  723. * @param array $args Arguments passed by the setting
  724. */
  725. function monsterinsights_rich_editor_callback( $args ) {
  726. $monsterinsights_option = monsterinsights_get_option( $args['id'] );
  727. if ( $monsterinsights_option ) {
  728. $value = $monsterinsights_option;
  729. } else {
  730. if( ! empty( $args['allow_blank'] ) && empty( $monsterinsights_option ) ) {
  731. $value = '';
  732. } else {
  733. $value = isset( $args['std'] ) ? $args['std'] : '';
  734. }
  735. }
  736. $rows = isset( $args['size'] ) ? $args['size'] : 20;
  737. $class = monsterinsights_sanitize_html_class( $args['field_class'] );
  738. ob_start();
  739. wp_editor( stripslashes( $value ), 'monsterinsights_settings_' . esc_attr( $args['id'] ), array( 'textarea_name' => 'monsterinsights_settings[' . esc_attr( $args['id'] ) . ']', 'textarea_rows' => absint( $rows ), 'editor_class' => $class ) );
  740. $html = ob_get_clean();
  741. $html .= '<br/><p class="description"> ' . wp_kses_post( $args['desc'] ) . '</p>';
  742. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  743. }
  744. /**
  745. * Descriptive text callback.
  746. *
  747. * Renders descriptive text onto the settings field.
  748. *
  749. * @since 6.0.0
  750. * @param array $args Arguments passed by the setting
  751. * @return void
  752. */
  753. function monsterinsights_descriptive_text_callback( $args ) {
  754. $html = wp_kses_post( $args['desc'] );
  755. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  756. }
  757. /**
  758. * Notice Callback
  759. *
  760. * Renders notice fields.
  761. *
  762. * @since 6.0.0
  763. * @param array $args Arguments passed by the setting
  764. *
  765. * @return void
  766. */
  767. function monsterinsights_notice_callback( $args ) {
  768. $html = monsterinsights_get_message( $args['notice_type'], $args['desc'] );
  769. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  770. }
  771. /**
  772. * Upgrade Notice Callback
  773. *
  774. * Renders upgrade notice fields.
  775. *
  776. * @since 6.1.7
  777. * @param array $args Arguments passed by the setting
  778. *
  779. * @return void
  780. */
  781. function monsterinsights_upgrade_notice_callback( $args ) {
  782. $html = '<div class="monsterinsights-upsell-box"><h2>' . esc_html( $args['name' ] ) . '</h2>'
  783. . '<p class="monsterinsights-upsell-lite-text">' . $args['desc'] . '</p>'
  784. . '<p class="monsterinsights-upsell-button-par"><a href="'. monsterinsights_get_upgrade_link( 'settings-page', 'settings-page-upgrade-cta' ) .'" class="monsterinsights-upsell-box-button button button-primary">' . __( 'Click here to Upgrade', 'google-analytics-for-wordpress' ) . '</a></p>'
  785. . '</div>';
  786. return apply_filters( 'monsterinsights_after_setting_output', $html, $args );
  787. }
  788. /**
  789. * Hook Callback
  790. *
  791. * Adds a do_action() hook in place of the field
  792. *
  793. * @since 6.0.0
  794. * @param array $args Arguments passed by the setting
  795. * @return void
  796. */
  797. function monsterinsights_hook_callback( $args ) {
  798. do_action( 'monsterinsights_' . $args['id'], $args );
  799. return '';
  800. }
  801. /**
  802. * Missing Callback
  803. *
  804. * If a function is missing for settings callbacks alert the user.
  805. *
  806. * @since 6.0.0
  807. * @param array $args Arguments passed by the setting
  808. * @return void
  809. */
  810. function monsterinsights_missing_callback($args) {
  811. return sprintf(
  812. __( 'The callback function used for the %s setting is missing.', 'google-analytics-for-wordpress' ),
  813. '<strong>' . $args['id'] . '</strong>'
  814. );
  815. }
  816. /**
  817. * Render Submit Button
  818. *
  819. * If there's a saveable field on the page, show save button.
  820. *
  821. * @since 6.0.0
  822. * @param array $args Arguments passed by the setting
  823. * @return void
  824. */
  825. function monsterinsights_render_submit_field( $section, $page = 'tracking' ) {
  826. $html = '';
  827. $settings = monsterinsights_get_registered_settings();
  828. if ( is_array( $settings ) && ! empty( $settings[$section] ) && is_array( $settings[$section] ) ) {
  829. $non_setting_types = monsterinsights_get_non_setting_types();
  830. $submit_button = false;
  831. foreach ( $settings[$section] as $setting ) {
  832. if ( ! empty( $non_setting_types ) && ! empty( $setting['type'] ) && ! in_array( $setting['type'], $non_setting_types ) ) {
  833. if ( empty( $setting['faux'] ) ) {
  834. $submit_button = true;
  835. break;
  836. }
  837. }
  838. }
  839. if ( $submit_button ) {
  840. $html .= '<input type="hidden" name="monsterinsights_settings_tab" value="' . esc_attr( $page ). '"/>';
  841. $html .= '<input type="hidden" name="monsterinsights_settings_sub_tab" value="' . esc_attr( $section ) . '"/>';
  842. $html .= wp_nonce_field( 'monsterinsights-settings-nonce', 'monsterinsights-settings-nonce', true, false );
  843. $html .= get_submit_button( esc_html__( 'Save Changes', 'google-analytics-for-wordpress' ), 'primary', 'monsterinsights-settings-submit', false );
  844. }
  845. $html = apply_filters( 'monsterinsights_html_after_submit_field', $html, $page, $section );
  846. }
  847. return $html;
  848. }
  849. /**
  850. * @todo docbloc
  851. */
  852. function monsterinsights_render_field( $args ) {
  853. $output = '';
  854. $output .='<tr id="monsterinsights-input-' . monsterinsights_sanitize_key( $args['id'] ) .'">';
  855. if ( ! empty( $args['name'] ) && empty( $args['no_label'] ) ) {
  856. $output .= '<th scope="row">';
  857. $output .='<label for="monsterinsights_settings[' . monsterinsights_sanitize_key( $args['id'] ) . ']">' . esc_html( $args["name"] ) . '</label>';
  858. $output .= '</th>';
  859. }
  860. if ( empty( $args['no_label'] ) ) {
  861. $output .= '<td>';
  862. } else {
  863. $output .= '<td colspan="2">';
  864. }
  865. $render = ! empty( $args['type'] ) && function_exists( 'monsterinsights_' . $args['type'] . '_callback' ) ? 'monsterinsights_' . $args['type'] . '_callback' : 'monsterinsights_missing_callback';
  866. $output .= call_user_func( $render, $args );
  867. $output .= '</td>';
  868. $output .= '</tr>';
  869. return $output;
  870. }
  871. /**
  872. * @todo docbloc
  873. */
  874. function monsterinsights_add_setting_tooltip( $html, $args ) { // @todo: enqueue tooltips
  875. if ( ! empty( $args['tooltip_title'] ) && ! empty( $args['tooltip_desc'] ) ) {
  876. $tooltip = '<span alt="f223" class="monsterinsights-help-tip dashicons dashicons-editor-help" title="<strong>' . $args['tooltip_title'] . '</strong>: ' . $args['tooltip_desc'] . '"></span>';
  877. $html .= $tooltip;
  878. }
  879. return $html;
  880. }
  881. add_filter( 'monsterinsights_after_setting_output', 'monsterinsights_add_setting_tooltip', 10, 2 );
  882. /**
  883. * @todo docbloc
  884. */
  885. function monsterinsights_get_settings_notices( $delete_on_retrieve = true ) {
  886. $notices = get_transient( 'monsterinsights_settings_notices' );
  887. if ( $delete_on_retrieve ) {
  888. delete_transient( 'monsterinsights_settings_notices' );
  889. }
  890. return $notices;
  891. }
  892. /**
  893. * @todo docbloc
  894. */
  895. function monsterinsights_add_settings_notice( $name, $type = 'success', $message = '' ) {
  896. $notices = get_transient( 'monsterinsights_settings_notices' );
  897. if ( empty( $notices ) ) {
  898. $notices = array();
  899. $notices[ $name ] = array( "type" => $type, "message" => $message );
  900. } else {
  901. $notices[ $name ] = array( "type" => $type, "message" => $message );
  902. }
  903. set_transient( 'monsterinsights_settings_notices', $notices );
  904. }
  905. /**
  906. * @todo docbloc
  907. */
  908. function monsterinsights_remove_settings_notice( $name ) {
  909. $notices = get_transient( 'monsterinsights_settings_notices' );
  910. $found = false;
  911. if ( ! empty( $notices ) ) {
  912. if ( isset( $notices[ $name] ) ) {
  913. unset( $notices[ $name] );
  914. set_transient( 'monsterinsights_settings_notices', $notices );
  915. $found = true;
  916. } else {
  917. set_transient( 'monsterinsights_settings_notices', $notices );
  918. }
  919. }
  920. return $found;
  921. }
  922. /**
  923. * @todo docbloc
  924. */
  925. function monsterinsights_get_non_setting_types(){
  926. return apply_filters( 'monsterinsights_non_setting_types', array( 'descriptive_text', 'hook', 'upgrade_notice', 'install_notice', 'notice' ) );
  927. }