/includes/admin/settings/settings-api.php

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