NEXT craftinamerica.org. Base setup for headless wordpress https://www.craftinamerica.org
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

AdminPage.php 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. <?php
  2. /**
  3. * Administration page base class.
  4. */
  5. abstract class scbAdminPage {
  6. /** Page args
  7. * $page_title string (mandatory)
  8. * $parent (string) (default: options-general.php)
  9. * $capability (string) (default: 'manage_options')
  10. * $menu_title (string) (default: $page_title)
  11. * $submenu_title (string) (default: $menu_title)
  12. * $page_slug (string) (default: sanitized $page_title)
  13. * $toplevel (string) If not empty, will create a new top level menu (for expected values see http://codex.wordpress.org/Administration_Menus#Using_add_submenu_page)
  14. * - $icon_url (string) URL to an icon for the top level menu
  15. * - $position (int) Position of the toplevel menu (caution!)
  16. * $screen_icon (string) The icon type to use in the screen header
  17. * $nonce string (default: $page_slug)
  18. * $action_link (string|bool) Text of the action link on the Plugins page (default: 'Settings')
  19. * $admin_action_priority int The priority that the admin_menu action should be executed at (default: 10)
  20. */
  21. protected $args;
  22. // URL to the current plugin directory.
  23. // Useful for adding css and js files
  24. protected $plugin_url;
  25. // Created at page init
  26. protected $pagehook;
  27. // scbOptions object holder
  28. // Normally, it's used for storing formdata
  29. protected $options;
  30. protected $option_name;
  31. // l10n
  32. protected $textdomain;
  33. // ____________REGISTRATION COMPONENT____________
  34. private static $registered = array();
  35. /**
  36. * Registers class of page.
  37. *
  38. * @param string $class
  39. * @param string $file
  40. * @param object $options (optional) A scbOptions object.
  41. *
  42. * @return bool
  43. */
  44. public static function register( $class, $file, $options = null ) {
  45. if ( isset( self::$registered[ $class ] ) ) {
  46. return false;
  47. }
  48. self::$registered[ $class ] = array( $file, $options );
  49. add_action( '_admin_menu', array( __CLASS__, '_pages_init' ) );
  50. return true;
  51. }
  52. /**
  53. * Replaces class of page.
  54. *
  55. * @param string $old_class
  56. * @param string $new_class
  57. *
  58. * @return bool
  59. */
  60. public static function replace( $old_class, $new_class ) {
  61. if ( ! isset( self::$registered[ $old_class ] ) ) {
  62. return false;
  63. }
  64. self::$registered[ $new_class ] = self::$registered[ $old_class ];
  65. unset( self::$registered[ $old_class ] );
  66. return true;
  67. }
  68. /**
  69. * Removes class of page.
  70. *
  71. * @param string $class
  72. *
  73. * @return bool
  74. */
  75. public static function remove( $class ) {
  76. if ( ! isset( self::$registered[ $class ] ) ) {
  77. return false;
  78. }
  79. unset( self::$registered[ $class ] );
  80. return true;
  81. }
  82. /**
  83. * Instantiates classes of pages.
  84. *
  85. * @return void
  86. */
  87. public static function _pages_init() {
  88. foreach ( self::$registered as $class => $args ) {
  89. new $class( $args[0], $args[1] );
  90. }
  91. }
  92. // ____________MAIN METHODS____________
  93. /**
  94. * Constructor.
  95. *
  96. * @param string|bool $file (optional)
  97. * @param object $options (optional) A scbOptions object.
  98. *
  99. * @return void
  100. */
  101. public function __construct( $file = false, $options = null ) {
  102. if ( is_a( $options, 'scbOptions' ) ) {
  103. $this->options = $options;
  104. }
  105. $this->setup();
  106. $this->check_args();
  107. if ( isset( $this->option_name ) ) {
  108. add_action( 'admin_init', array( $this, 'option_init' ) );
  109. add_action( 'admin_notices', 'settings_errors' );
  110. }
  111. add_action( 'admin_menu', array( $this, 'page_init' ), $this->args['admin_action_priority'] );
  112. // Commented out due to deprecated notice.
  113. // add_filter( 'contextual_help', array( $this, '_contextual_help' ), 10, 2 );
  114. if ( $file ) {
  115. $this->file = $file;
  116. $this->plugin_url = plugin_dir_url( $file );
  117. if ( $this->args['action_link'] ) {
  118. add_filter( 'plugin_action_links_' . plugin_basename( $file ), array( $this, '_action_link' ) );
  119. }
  120. }
  121. }
  122. /**
  123. * This is where all the page args can be set.
  124. *
  125. * @return void
  126. */
  127. protected function setup() { }
  128. /**
  129. * Called when the page is loaded, but before any rendering.
  130. * Useful for calling $screen->add_help_tab() etc.
  131. *
  132. * @return void
  133. */
  134. public function page_loaded() {
  135. $this->form_handler();
  136. }
  137. /**
  138. * This is where the css and js go.
  139. * Both wp_enqueue_*() and inline code can be added.
  140. *
  141. * @return void
  142. */
  143. public function page_head() { }
  144. /**
  145. * This is where the contextual help goes.
  146. *
  147. * @return string
  148. */
  149. protected function page_help() { }
  150. /**
  151. * A generic page header.
  152. *
  153. * @return void
  154. */
  155. protected function page_header() {
  156. echo "<div class='wrap'>\n";
  157. echo html( 'h2', $this->args['page_title'] );
  158. }
  159. /**
  160. * This is where the page content goes.
  161. *
  162. * @return void
  163. */
  164. abstract protected function page_content();
  165. /**
  166. * A generic page footer.
  167. *
  168. * @return void
  169. */
  170. protected function page_footer() {
  171. echo "</div>\n";
  172. }
  173. /**
  174. * This is where the form data should be validated.
  175. *
  176. * @param array $new_data
  177. * @param array $old_data
  178. *
  179. * @return array
  180. */
  181. public function validate( $new_data, $old_data ) {
  182. return $new_data;
  183. }
  184. /**
  185. * Manually handle option saving ( use Settings API instead ).
  186. *
  187. * @return bool
  188. */
  189. protected function form_handler() {
  190. if ( empty( $_POST['submit'] ) && empty( $_POST['action'] ) ) {
  191. return false;
  192. }
  193. check_admin_referer( $this->nonce );
  194. if ( ! isset( $this->options ) ) {
  195. trigger_error( 'options handler not set', E_USER_WARNING );
  196. return false;
  197. }
  198. $new_data = wp_array_slice_assoc( $_POST, array_keys( $this->options->get_defaults() ) );
  199. $new_data = stripslashes_deep( $new_data );
  200. $new_data = $this->validate( $new_data, $this->options->get() );
  201. $this->options->set( $new_data );
  202. add_action( 'admin_notices', array( $this, 'admin_msg' ) );
  203. return true;
  204. }
  205. /**
  206. * Manually generate a standard admin notice ( use Settings API instead ).
  207. *
  208. * @param string $msg (optional)
  209. * @param string $class (optional)
  210. *
  211. * @return void
  212. */
  213. public function admin_msg( $msg = '', $class = 'updated' ) {
  214. if ( empty( $msg ) ) {
  215. $msg = __( 'Settings <strong>saved</strong>.', $this->textdomain );
  216. }
  217. echo scb_admin_notice( $msg, $class );
  218. }
  219. // ____________UTILITIES____________
  220. /**
  221. * Generates a form submit button.
  222. *
  223. * @param string|array $value (optional) Button text or array of arguments.
  224. * @param string $action (optional)
  225. * @param string $class (optional)
  226. *
  227. * @return string
  228. */
  229. public function submit_button( $value = '', $action = 'submit', $class = 'button' ) {
  230. $args = is_array( $value ) ? $value : compact( 'value', 'action', 'class' );
  231. $args = wp_parse_args( $args, array(
  232. 'value' => null,
  233. 'action' => $action,
  234. 'class' => $class,
  235. ) );
  236. return get_submit_button( $args['value'], $args['class'], $args['action'] );
  237. }
  238. /**
  239. * Mimics scbForms::form_wrap()
  240. *
  241. * $this->form_wrap( $content ); // generates a form with a default submit button
  242. *
  243. * $this->form_wrap( $content, false ); // generates a form with no submit button
  244. *
  245. * // the second argument is sent to submit_button()
  246. * $this->form_wrap( $content, array(
  247. * 'text' => 'Save changes',
  248. * 'name' => 'action',
  249. * ) );
  250. *
  251. * @see scbForms::form_wrap()
  252. *
  253. * @param string $content
  254. * @param boolean|string|array $submit_button (optional)
  255. *
  256. * @return string
  257. */
  258. public function form_wrap( $content, $submit_button = true ) {
  259. if ( is_array( $submit_button ) ) {
  260. $content .= $this->submit_button( $submit_button );
  261. } else if ( true === $submit_button ) {
  262. $content .= $this->submit_button();
  263. } else if ( false !== strpos( $submit_button, '<input' ) ) {
  264. $content .= $submit_button;
  265. } else if ( false !== strpos( $submit_button, '<button' ) ) {
  266. $content .= $submit_button;
  267. } else if ( false !== $submit_button ) {
  268. $button_args = array_slice( func_get_args(), 1 );
  269. $content .= call_user_func_array( array( $this, 'submit_button' ), $button_args );
  270. }
  271. return scbForms::form_wrap( $content, $this->nonce );
  272. }
  273. /**
  274. * Generates a table wrapped in a form.
  275. *
  276. * @param array $rows
  277. * @param array|boolean $formdata (optional)
  278. *
  279. * @return string
  280. */
  281. public function form_table( $rows, $formdata = false ) {
  282. $output = '';
  283. foreach ( $rows as $row ) {
  284. $output .= $this->table_row( $row, $formdata );
  285. }
  286. $output = $this->form_table_wrap( $output );
  287. return $output;
  288. }
  289. /**
  290. * Wraps the given content in a <form><table>
  291. *
  292. * @param string $content
  293. *
  294. * @return string
  295. */
  296. public function form_table_wrap( $content ) {
  297. $output = $this->table_wrap( $content );
  298. $output = $this->form_wrap( $output );
  299. return $output;
  300. }
  301. /**
  302. * Generates a form table.
  303. *
  304. * @param array $rows
  305. * @param array|boolean $formdata (optional)
  306. *
  307. * @return string
  308. */
  309. public function table( $rows, $formdata = false ) {
  310. $output = '';
  311. foreach ( $rows as $row ) {
  312. $output .= $this->table_row( $row, $formdata );
  313. }
  314. $output = $this->table_wrap( $output );
  315. return $output;
  316. }
  317. /**
  318. * Generates a table row.
  319. *
  320. * @param array $args
  321. * @param array|boolean $formdata (optional)
  322. *
  323. * @return string
  324. */
  325. public function table_row( $args, $formdata = false ) {
  326. return $this->row_wrap( $args['title'], $this->input( $args, $formdata ) );
  327. }
  328. /**
  329. * Mimic scbForms inheritance.
  330. *
  331. * @see scbForms
  332. *
  333. * @param string $method
  334. * @param array $args
  335. *
  336. * @return mixed
  337. */
  338. public function __call( $method, $args ) {
  339. if ( in_array( $method, array( 'input', 'form' ) ) ) {
  340. if ( empty( $args[1] ) && isset( $this->options ) ) {
  341. $args[1] = $this->options->get();
  342. }
  343. if ( 'form' == $method ) {
  344. $args[2] = $this->nonce;
  345. }
  346. }
  347. return call_user_func_array( array( 'scbForms', $method ), $args );
  348. }
  349. /**
  350. * Wraps a string in a <script> tag.
  351. *
  352. * @param string $string
  353. *
  354. * @return string
  355. */
  356. public function js_wrap( $string ) {
  357. return html( "script type='text/javascript'", $string );
  358. }
  359. /**
  360. * Wraps a string in a <style> tag.
  361. *
  362. * @param string $string
  363. *
  364. * @return string
  365. */
  366. public function css_wrap( $string ) {
  367. return html( "style type='text/css'", $string );
  368. }
  369. // ____________INTERNAL METHODS____________
  370. /**
  371. * Registers a page.
  372. *
  373. * @return void
  374. */
  375. public function page_init() {
  376. if ( ! $this->args['toplevel'] ) {
  377. $this->pagehook = add_submenu_page(
  378. $this->args['parent'],
  379. $this->args['page_title'],
  380. $this->args['menu_title'],
  381. $this->args['capability'],
  382. $this->args['page_slug'],
  383. array( $this, '_page_content_hook' )
  384. );
  385. } else {
  386. $func = 'add_' . $this->args['toplevel'] . '_page';
  387. $this->pagehook = $func(
  388. $this->args['page_title'],
  389. $this->args['menu_title'],
  390. $this->args['capability'],
  391. $this->args['page_slug'],
  392. null,
  393. $this->args['icon_url'],
  394. $this->args['position']
  395. );
  396. add_submenu_page(
  397. $this->args['page_slug'],
  398. $this->args['page_title'],
  399. $this->args['submenu_title'],
  400. $this->args['capability'],
  401. $this->args['page_slug'],
  402. array( $this, '_page_content_hook' )
  403. );
  404. }
  405. if ( ! $this->pagehook ) {
  406. return;
  407. }
  408. add_action( 'load-' . $this->pagehook, array( $this, 'page_loaded' ) );
  409. add_action( 'admin_print_styles-' . $this->pagehook, array( $this, 'page_head' ) );
  410. }
  411. /**
  412. * Registers a option.
  413. *
  414. * @return void
  415. */
  416. public function option_init() {
  417. register_setting( $this->option_name, $this->option_name, array( $this, 'validate' ) );
  418. }
  419. /**
  420. * Checks page args.
  421. *
  422. * @return void
  423. */
  424. private function check_args() {
  425. if ( empty( $this->args['page_title'] ) ) {
  426. trigger_error( 'Page title cannot be empty', E_USER_WARNING );
  427. }
  428. $this->args = wp_parse_args( $this->args, array(
  429. 'toplevel' => '',
  430. 'position' => null,
  431. 'icon_url' => '',
  432. 'parent' => 'options-general.php',
  433. 'capability' => 'manage_options',
  434. 'menu_title' => $this->args['page_title'],
  435. 'page_slug' => '',
  436. 'nonce' => '',
  437. 'action_link' => __( 'Settings', $this->textdomain ),
  438. 'admin_action_priority' => 10,
  439. ) );
  440. if ( empty( $this->args['submenu_title'] ) ) {
  441. $this->args['submenu_title'] = $this->args['menu_title'];
  442. }
  443. if ( empty( $this->args['page_slug'] ) ) {
  444. $this->args['page_slug'] = sanitize_title_with_dashes( $this->args['menu_title'] );
  445. }
  446. if ( empty( $this->args['nonce'] ) ) {
  447. $this->nonce = $this->args['page_slug'];
  448. }
  449. }
  450. /**
  451. * Adds contextual help.
  452. *
  453. * @param string $help
  454. * @param string|object $screen
  455. *
  456. * @return string
  457. */
  458. public function _contextual_help( $help, $screen ) {
  459. if ( is_object( $screen ) ) {
  460. $screen = $screen->id;
  461. }
  462. $actual_help = $this->page_help();
  463. if ( $screen == $this->pagehook && $actual_help ) {
  464. return $actual_help;
  465. }
  466. return $help;
  467. }
  468. /**
  469. * Displays page content.
  470. *
  471. * @return void
  472. */
  473. public function _page_content_hook() {
  474. $this->page_header();
  475. $this->page_content();
  476. $this->page_footer();
  477. }
  478. /**
  479. * Adds an action link.
  480. *
  481. * @param array $links
  482. *
  483. * @return array
  484. */
  485. public function _action_link( $links ) {
  486. $url = add_query_arg( 'page', $this->args['page_slug'], admin_url( $this->args['parent'] ) );
  487. $links[] = html_link( $url, $this->args['action_link'] );
  488. return $links;
  489. }
  490. }