PageRenderTime 26ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/lib/plugin/settings.php

https://github.com/mgsisk/webcomic
PHP | 459 lines | 263 code | 66 blank | 130 comment | 24 complexity | b537cc0899fc47feee8d615fab691dff MD5 | raw file
  1. <?php
  2. /**
  3. * Plugin settings functionality
  4. *
  5. * @package Webcomic
  6. */
  7. namespace Mgsisk\Webcomic\Plugin;
  8. /**
  9. * Add plugin settings hooks.
  10. *
  11. * @return void
  12. */
  13. function settings() {
  14. register_deactivation_hook( webcomic( 'file' ), __NAMESPACE__ . '\hook_uninstall' );
  15. add_filter( 'plugins_loaded', __NAMESPACE__ . '\hook_install' );
  16. add_filter( 'admin_menu', __NAMESPACE__ . '\hook_add_settings_page' );
  17. add_filter( 'admin_init', __NAMESPACE__ . '\hook_register_options' );
  18. add_filter( 'admin_init', __NAMESPACE__ . '\hook_add_settings_section' );
  19. add_filter( 'admin_init', __NAMESPACE__ . '\hook_add_field_uninstall', 999 );
  20. add_filter( 'admin_init', __NAMESPACE__ . '\hook_add_field_debug', 999 );
  21. add_filter( 'admin_head', __NAMESPACE__ . '\hook_add_help_sidebar' );
  22. add_filter( 'admin_head', __NAMESPACE__ . '\hook_add_help_overview' );
  23. add_filter( 'admin_head', __NAMESPACE__ . '\hook_add_help_details' );
  24. add_filter( 'admin_notices', __NAMESPACE__ . '\hook_inkblot_component_alert' ); // NOTE For compatibility with Inkblot 4.
  25. add_filter( 'admin_notices', __NAMESPACE__ . '\hook_uninstall_alert' );
  26. add_filter( 'network_admin_notices', __NAMESPACE__ . '\hook_uninstall_network_alert' );
  27. add_filter( 'all_admin_notices', __NAMESPACE__ . '\hook_display_admin_notices' );
  28. add_filter( 'sanitize_option_webcomic', __NAMESPACE__ . '\hook_sanitize_options' );
  29. add_filter( 'sanitize_option_webcomic', __NAMESPACE__ . '\hook_sanitize_components' );
  30. add_filter( 'sanitize_option_webcomic', __NAMESPACE__ . '\hook_sanitize_uninstall' );
  31. add_filter( 'sanitize_option_webcomic', __NAMESPACE__ . '\hook_sanitize_debug' );
  32. add_filter( 'plugin_row_meta', __NAMESPACE__ . '\hook_add_plugin_links', 10, 4 );
  33. }
  34. /**
  35. * Uninstall the plugin.
  36. *
  37. * @param bool $network Whether this is a network deactivation.
  38. * @param int $site The site the plugin is being deactivated on.
  39. * @return void
  40. */
  41. function hook_uninstall( bool $network, int $site = 0 ) {
  42. if ( $network ) {
  43. $sites = get_sites(
  44. [
  45. 'fields' => 'ids',
  46. ]
  47. );
  48. foreach ( $sites as $site ) {
  49. hook_uninstall( false, $site );
  50. }
  51. } elseif ( is_multisite() ) {
  52. if ( ! $site ) {
  53. $site = get_current_blog_id();
  54. }
  55. switch_to_blog( $site );
  56. }
  57. if ( webcomic( 'option.uninstall' ) ) {
  58. $path = dirname( __DIR__ );
  59. $components = array_reverse( array_map( 'basename', array_unique( array_merge( [ $path . '/collection', $path . '/compat' ], glob( $path . '/*', GLOB_ONLYDIR ) ) ) ) );
  60. foreach ( $components as $component ) {
  61. webcomic_load( [ $component ] );
  62. /* This action is documented in Mgsisk\Webcomic\Plugin\hook_sanitize_components() */
  63. do_action( 'webcomic_deactivate_' . $component );
  64. }
  65. delete_option( 'webcomic' );
  66. }
  67. if ( is_multisite() ) {
  68. restore_current_blog();
  69. }
  70. }
  71. /**
  72. * Install the plugin.
  73. *
  74. * @return void
  75. */
  76. function hook_install() {
  77. if ( ! webcomic( 'option.install' ) ) {
  78. return;
  79. }
  80. update_option( 'webcomic', [] );
  81. }
  82. /**
  83. * Add the settings page.
  84. *
  85. * @return void
  86. */
  87. function hook_add_settings_page() {
  88. add_options_page(
  89. __( 'Webcomic Settings', 'webcomic' ),
  90. __( 'Webcomic', 'webcomic' ),
  91. 'manage_options',
  92. 'webcomic_options',
  93. function() {
  94. require __DIR__ . '/settings-inc-page.php';
  95. }
  96. );
  97. }
  98. /**
  99. * Register the plugin options.
  100. *
  101. * @return void
  102. */
  103. function hook_register_options() {
  104. register_setting( 'webcomic', 'webcomic' );
  105. }
  106. /**
  107. * Add the settings section.
  108. *
  109. * @return void
  110. */
  111. function hook_add_settings_section() {
  112. add_settings_section(
  113. 'webcomic_general',
  114. '',
  115. function() {
  116. $args = [
  117. 'file' => __DIR__ . '/settings-inc-section.php',
  118. 'option' => webcomic( 'option.components' ),
  119. 'label_for' => 'webcomic[components]',
  120. 'css_class' => [ 'inactive', 'active' ],
  121. 'uninstall' => '',
  122. ];
  123. if ( webcomic( 'option.uninstall' ) ) {
  124. $args['uninstall'] = __( 'Deactivating a component will delete all data related to it.', 'webcomic' );
  125. }
  126. require $args['file'];
  127. },
  128. 'webcomic_options'
  129. );
  130. }
  131. /**
  132. * Add the uninstall setting field.
  133. *
  134. * @return void
  135. */
  136. function hook_add_field_uninstall() {
  137. add_settings_field(
  138. 'webcomic_uninstall',
  139. __( 'Uninstall', 'webcomic' ),
  140. function( $args ) {
  141. require $args['file'];
  142. },
  143. 'webcomic_options',
  144. 'webcomic_general', [
  145. 'file' => __DIR__ . '/settings-inc-field-uninstall.php',
  146. 'option' => webcomic( 'option.uninstall' ),
  147. 'label_for' => 'webcomic[uninstall]',
  148. ]
  149. );
  150. }
  151. /**
  152. * Add the debug setting field.
  153. *
  154. * @return void
  155. */
  156. function hook_add_field_debug() {
  157. if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
  158. return;
  159. }
  160. add_settings_field(
  161. 'webcomic_debug',
  162. __( 'Debug', 'webcomic' ),
  163. function( $args ) {
  164. require $args['file'];
  165. },
  166. 'webcomic_options',
  167. 'webcomic_general', [
  168. 'file' => __DIR__ . '/settings-inc-field-debug.php',
  169. 'option' => webcomic( 'option.debug' ),
  170. 'label_for' => 'webcomic[debug]',
  171. ]
  172. );
  173. }
  174. /**
  175. * Add the help sidebar.
  176. *
  177. * @return void
  178. */
  179. function hook_add_help_sidebar() {
  180. $screen = get_current_screen();
  181. if ( 'settings_page_webcomic_options' !== $screen->id ) {
  182. return;
  183. }
  184. $screen->set_help_sidebar( webcomic_help() );
  185. }
  186. /**
  187. * Add the overview help tab.
  188. *
  189. * @return void
  190. */
  191. function hook_add_help_overview() {
  192. $screen = get_current_screen();
  193. if ( 'settings_page_webcomic_options' !== $screen->id ) {
  194. return;
  195. }
  196. $screen->add_help_tab(
  197. [
  198. 'id' => 'overview',
  199. 'title' => __( 'Overview', 'webcomic' ),
  200. 'callback' => function() {
  201. require __DIR__ . '/settings-inc-help-overview.php';
  202. },
  203. ]
  204. );
  205. }
  206. /**
  207. * Add the details help tab.
  208. *
  209. * @return void
  210. */
  211. function hook_add_help_details() {
  212. $screen = get_current_screen();
  213. if ( 'settings_page_webcomic_options' !== $screen->id ) {
  214. return;
  215. }
  216. $screen->add_help_tab(
  217. [
  218. 'id' => 'details',
  219. 'title' => __( 'Details', 'webcomic' ),
  220. 'callback' => function() {
  221. $args = [
  222. 'file' => __DIR__ . '/settings-inc-help-details.php',
  223. 'option' => webcomic( 'option' ),
  224. ];
  225. ksort( $args['option'] );
  226. require $args['file'];
  227. },
  228. ]
  229. );
  230. }
  231. /**
  232. * Add a component alert message if Inkblot 4 is the active theme.
  233. *
  234. * @return void
  235. */
  236. function hook_inkblot_component_alert() {
  237. $theme = wp_get_theme();
  238. if ( 'inkblot' !== strtolower( $theme->name ) ) {
  239. $theme = wp_get_theme( $theme->template );
  240. }
  241. if ( 'inkblot' !== strtolower( $theme->name ) || '4' !== $theme->version[0] ) {
  242. return;
  243. }
  244. $missing = array_diff( [ 'character', 'collection', 'commerce', 'compat', 'restrict', 'storyline', 'transcribe' ], webcomic( 'option.components' ) );
  245. if ( ! $missing ) {
  246. return;
  247. }
  248. // Translators: 1: Theme name. 2: Theme major version. 3: Disabled plugin components.
  249. webcomic_notice( sprintf( __( '%1$s %2$s requires these disabled Webcomic components: %3$s', 'webcomic' ), $theme->name, $theme->version[0], ucwords( implode( ', ', $missing ) ) ), 'warning' );
  250. }
  251. /**
  252. * Add an uninstall alert message to the Plugins screen.
  253. *
  254. * @return void
  255. */
  256. function hook_uninstall_alert() {
  257. if ( 'plugins' !== get_current_screen()->id || ! webcomic( 'option.uninstall' ) ) {
  258. return;
  259. }
  260. webcomic_notice( __( 'Deactivating Webcomic will delete all data related to it.', 'webcomic' ), 'warning' );
  261. }
  262. /**
  263. * Add an uninstall alert message to the network Plugins screen.
  264. *
  265. * @return void
  266. */
  267. function hook_uninstall_network_alert() {
  268. if ( 'plugins-network' !== get_current_screen()->id ) {
  269. return;
  270. }
  271. $uninstall = 0;
  272. $sites = get_sites(
  273. [
  274. 'fields' => 'ids',
  275. ]
  276. );
  277. foreach ( $sites as $site ) {
  278. $options = get_blog_option( $site, 'webcomic', [] );
  279. if ( ! $options['uninstall'] ) {
  280. continue;
  281. }
  282. $uninstall++;
  283. }
  284. if ( ! $uninstall ) {
  285. return;
  286. }
  287. // Translators: The number of sites with the uninstall option enabled.
  288. webcomic_notice( sprintf( _n( 'Deactivating Webcomic will delete all data related to it on %s site.', 'Deactivating Webcomic will delete all data related to it on %s sites.', $uninstall, 'webcomic' ), number_format_i18n( $uninstall ) ), 'warning' );
  289. }
  290. /**
  291. * Display administrative notifications.
  292. *
  293. * @return void
  294. */
  295. function hook_display_admin_notices() {
  296. $notices = get_transient( 'webcomic_admin_notices' );
  297. if ( ! $notices ) {
  298. return;
  299. }
  300. delete_transient( 'webcomic_admin_notices' );
  301. foreach ( $notices as $notice ) {
  302. list( $class, $message ) = explode( '|', $notice, 2 );
  303. $class = esc_attr( $class );
  304. echo "<div class='notice notice-{$class} is-dismissible'><p>{$message}</p></div>"; // WPCS: xss ok.
  305. }
  306. }
  307. /**
  308. * Ensure only allowed options are set.
  309. *
  310. * @param array $options The submitted options.
  311. * @return array
  312. */
  313. function hook_sanitize_options( array $options ) : array {
  314. $options += webcomic( 'option' );
  315. return array_intersect_key( $options, array_flip( [ 'version', 'upgrade', 'debug', 'uninstall', 'components', 'collections', 'compat' ] ) );
  316. }
  317. /**
  318. * Sanitize the component field.
  319. *
  320. * @param array $options The submitted options.
  321. * @return array
  322. */
  323. function hook_sanitize_components( array $options ) : array {
  324. $old_components = webcomic( 'option.components' );
  325. $options['components'] = array_merge(
  326. [ 'collection' ],
  327. array_intersect( $options['components'], [ 'alert', 'character', 'commerce', 'compat', 'integrate', 'restrict', 'storyline', 'transcribe', 'twitter' ] )
  328. );
  329. foreach ( array_diff( $old_components, $options['components'] ) as $component ) {
  330. /**
  331. * Deactivate a component.
  332. *
  333. * This action provides a way for components to perform component-specific
  334. * cleanup and other actions before deactivation.
  335. */
  336. do_action( 'webcomic_deactivate_' . $component );
  337. }
  338. foreach ( array_diff( $options['components'], $old_components ) as $component ) {
  339. webcomic_load( [ $component ] );
  340. /**
  341. * Activate a component.
  342. *
  343. * This action provides a way for components to perform component-specific
  344. * setup and other actions before activation.
  345. */
  346. do_action( 'webcomic_activate_' . $component );
  347. }
  348. return $options;
  349. }
  350. /**
  351. * Sanitize the uninstall field.
  352. *
  353. * @param array $options The submitted options.
  354. * @return array
  355. */
  356. function hook_sanitize_uninstall( array $options ) : array {
  357. $options['uninstall'] = (bool) $options['uninstall'];
  358. return $options;
  359. }
  360. /**
  361. * Sanitize the debug field.
  362. *
  363. * @param array $options The submitted options.
  364. * @return array
  365. */
  366. function hook_sanitize_debug( array $options ) : array {
  367. $options['debug'] = ( defined( 'WP_DEBUG' ) && WP_DEBUG && $options['debug'] );
  368. return $options;
  369. }
  370. /**
  371. * Display additional plugin links.
  372. *
  373. * @param array $meta The current plugin meta data.
  374. * @param string $file The current plugin file.
  375. * @param array $data The current plugin metadata.
  376. * @param string $context The current plugin context.
  377. * @return array
  378. */
  379. function hook_add_plugin_links( array $meta, string $file, array $data, string $context ) : array {
  380. if ( false === strpos( $file, '/webcomic.php' ) ) {
  381. return $meta;
  382. }
  383. $settings_url = esc_url(
  384. add_query_arg(
  385. [
  386. 'page' => 'webcomic_options',
  387. ], admin_url( 'options-general.php' )
  388. )
  389. );
  390. $meta['settings'] = "<a href='{$settings_url}'>" . esc_html__( 'Settings', 'webcomic' ) . '</a>';
  391. $meta['support'] = '<a href="https://mgsisk.com/#support" target="_blank">' . esc_html__( 'Support', 'webcomic' ) . '</a>';
  392. return $meta;
  393. }