PageRenderTime 57ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/class/Common/Compatibility/Compatibility.php

https://github.com/bradt/wp-migrate-db
PHP | 347 lines | 200 code | 54 blank | 93 comment | 44 complexity | d73fbe726c47e936c26c5b2f3e4fbebe MD5 | raw file
  1. <?php
  2. namespace DeliciousBrains\WPMDB\Common\Compatibility;
  3. class Compatibility {
  4. /**
  5. * @var string
  6. */
  7. protected $muplugin_class_dir;
  8. /**
  9. * @var string
  10. */
  11. protected $muplugin_dir;
  12. /**
  13. * @var
  14. */
  15. protected $default_whitelisted_plugins;
  16. public function __construct() {
  17. $this->muplugin_class_dir = plugin_dir_path( __FILE__ );
  18. $this->muplugin_dir = ( defined( 'WPMU_PLUGIN_DIR' ) && defined( 'WPMU_PLUGIN_URL' ) ) ? WPMU_PLUGIN_DIR : trailingslashit( WP_CONTENT_DIR ) . 'mu-plugins';
  19. add_action( 'admin_init', array( $this, 'wpmdbc_tgmpa_compatibility' ), 1 );
  20. add_filter( 'option_active_plugins', array( $this, 'wpmdbc_include_plugins' ) );
  21. add_filter( 'site_option_active_sitewide_plugins', array( $this, 'wpmdbc_include_site_plugins' ) );
  22. add_filter( 'stylesheet_directory', array( $this, 'wpmdbc_disable_theme' ) );
  23. add_filter( 'template_directory', array( $this, 'wpmdbc_disable_theme' ) );
  24. add_action( 'muplugins_loaded', array( $this, 'wpmdbc_set_default_whitelist' ), 5 );
  25. add_action( 'muplugins_loaded', array( $this, 'wpmdbc_plugins_loaded' ), 10 );
  26. add_action( 'after_setup_theme', array( $this, 'wpmdbc_after_theme_setup' ) );
  27. }
  28. /**
  29. * During the `wpmdb_flush` and `wpmdb_remote_flush` actions, start output buffer in case theme spits out errors
  30. */
  31. public function wpmdbc_plugins_loaded() {
  32. if ( $this->wpmdbc_is_wpmdb_flush_call() ) {
  33. ob_start();
  34. }
  35. }
  36. /**
  37. * During the `wpmdb_flush` and `wpmdb_remote_flush` actions, if buffer isn't empty, log content and flush buffer.
  38. */
  39. public function wpmdbc_after_theme_setup() {
  40. if ( $this->wpmdbc_is_wpmdb_flush_call() ) {
  41. if ( ob_get_length() ) {
  42. error_log( ob_get_clean() );
  43. }
  44. }
  45. }
  46. /**
  47. *
  48. * Disables the theme during MDB AJAX requests
  49. *
  50. * Called from the `stylesheet_directory` hook
  51. *
  52. * @param $stylesheet_dir
  53. *
  54. * @return string
  55. */
  56. public function wpmdbc_disable_theme( $stylesheet_dir ) {
  57. $force_enable_theme = apply_filters( 'wpmdb_compatibility_enable_theme', false );
  58. if ( $this->wpmdbc_is_compatibility_mode_request() && ! $force_enable_theme ) {
  59. $theme_dir = realpath( dirname( __FILE__ ) . '/../Compatibility' );
  60. $stylesheet = 'temp-theme';
  61. $theme_root = "$theme_dir/$stylesheet";
  62. return $theme_root;
  63. }
  64. return $stylesheet_dir;
  65. }
  66. public function wpmdbc_set_default_whitelist() {
  67. // Allow users to filter whitelisted plugins
  68. $filtered_plugins = apply_filters( 'wpmdb_compatibility_plugin_whitelist', array() );
  69. // List of default plugins that should be whitelisted. Can be partial names or slugs
  70. $wpmdb_plugins = array(
  71. 'wpmdb', // Some tweaks plugins start with this string
  72. 'wp-migrate-db',
  73. );
  74. $plugins = array_merge( $filtered_plugins, $wpmdb_plugins );
  75. $this->default_whitelisted_plugins = $plugins;
  76. }
  77. /**
  78. * Remove TGM Plugin Activation 'force_activation' admin_init action hook if present.
  79. *
  80. * This is to stop excluded plugins being deactivated after a migration, when a theme uses TGMPA to require a
  81. * plugin to be always active. Also applies to the WDS-Required-Plugins by removing `activate_if_not` action
  82. */
  83. public function wpmdbc_tgmpa_compatibility() {
  84. $remove_function = false;
  85. // run on wpmdb page
  86. if ( isset( $_GET['page'] ) && 'wp-migrate-db-pro' == $_GET['page'] ) {
  87. $remove_function = true;
  88. }
  89. // run on wpmdb ajax requests
  90. if ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $_POST['action'] ) && false !== strpos( $_POST['action'], 'wpmdb' ) ) {
  91. $remove_function = true;
  92. }
  93. if ( $remove_function ) {
  94. global $wp_filter;
  95. $admin_init_functions = $wp_filter['admin_init'];
  96. foreach ( $admin_init_functions as $priority => $functions ) {
  97. foreach ( $functions as $key => $function ) {
  98. // searching for function this way as can't rely on the calling class being named TGM_Plugin_Activation
  99. if ( false !== strpos( $key, 'force_activation' ) || false !== strpos( $key, 'activate_if_not' ) ) {
  100. if ( is_array( $wp_filter['admin_init'] ) ) {
  101. // for core versions prior to WP 4.7
  102. unset( $wp_filter['admin_init'][ $priority ][ $key ] );
  103. } else {
  104. unset( $wp_filter['admin_init']->callbacks[ $priority ][ $key ] );
  105. }
  106. return;
  107. }
  108. }
  109. }
  110. }
  111. }
  112. /**
  113. * remove blog-active plugins
  114. *
  115. * @param array $plugins numerically keyed array of plugin names
  116. *
  117. * @return array
  118. */
  119. public function wpmdbc_include_plugins( $plugins ) {
  120. if ( ! is_array( $plugins ) || empty( $plugins ) ) {
  121. return $plugins;
  122. }
  123. if ( ! $this->wpmdbc_is_compatibility_mode_request() ) {
  124. return $plugins;
  125. }
  126. $whitelist_plugins = $this->wpmdbc_get_whitelist_plugins();
  127. $default_whitelist = $this->default_whitelisted_plugins;
  128. foreach ( $plugins as $key => $plugin ) {
  129. if ( true === $this->wpmdbc_plugin_in_default_whitelist( $plugin, $default_whitelist ) || isset( $whitelist_plugins[ $plugin ] ) ) {
  130. continue;
  131. }
  132. unset( $plugins[ $key ] );
  133. }
  134. return $plugins;
  135. }
  136. /**
  137. * remove network-active plugins
  138. *
  139. * @param array $plugins array of plugins keyed by name (name=>timestamp pairs)
  140. *
  141. * @return array
  142. */
  143. public function wpmdbc_include_site_plugins( $plugins ) {
  144. if ( ! is_array( $plugins ) || empty( $plugins ) ) {
  145. return $plugins;
  146. }
  147. if ( ! $this->wpmdbc_is_compatibility_mode_request() ) {
  148. return $plugins;
  149. }
  150. $whitelist_plugins = $this->wpmdbc_get_whitelist_plugins();
  151. if ( ! $this->default_whitelisted_plugins ) {
  152. $this->wpmdbc_set_default_whitelist();
  153. }
  154. $default_whitelist = $this->default_whitelisted_plugins;
  155. foreach ( array_keys( $plugins ) as $plugin ) {
  156. if ( true === $this->wpmdbc_plugin_in_default_whitelist( $plugin, $default_whitelist ) || isset( $whitelist_plugins[ $plugin ] ) ) {
  157. continue;
  158. }
  159. unset( $plugins[ $plugin ] );
  160. }
  161. return $plugins;
  162. }
  163. /**
  164. *
  165. * Checks if the current request is a WPMDB request
  166. *
  167. * @return bool
  168. */
  169. public function is_wpmdb_ajax_call() {
  170. if ( ( defined( 'DOING_AJAX' ) && DOING_AJAX ) && ( isset( $_POST['action'] ) && false !== strpos( $_POST['action'], 'wpmdb' ) ) ) {
  171. return true;
  172. }
  173. return false;
  174. }
  175. /**
  176. * @return bool
  177. */
  178. public function wpmdbc_is_wpmdb_ajax_call() {
  179. return $this->is_wpmdb_ajax_call();
  180. }
  181. /**
  182. * Checks if the current request is a WPMDB REST API migration request.
  183. *
  184. * Uses `$_SERVER` global since we're attempting to grab the current
  185. * route _before_ `rest_api_init` is fired by WordPress core.
  186. *
  187. * @return bool
  188. */
  189. public function wpmdbc_is_wpmdb_rest_request() {
  190. $api_base = 'mdb-api/v1/';
  191. $request_uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
  192. if (false === strpos($request_uri, $api_base)) {
  193. return false;
  194. }
  195. $current_endpoint = explode($api_base, $request_uri);
  196. $current_endpoint = end($current_endpoint);
  197. $migration_endpoints = apply_filters(
  198. 'wpmdb_compatibility_mode_api_endpoints',
  199. [
  200. 'initiate-migration',
  201. 'verify-connection',
  202. 'finalize-migration',
  203. 'cancel-migration',
  204. 'mf-initiate-file-migration',
  205. 'mf-get-queue-items',
  206. 'mf-transfer-files',
  207. 'tpf-initiate-file-migration',
  208. 'tpf-get-queue-items',
  209. 'tpf-transfer-files',
  210. 'prepare-upload',
  211. 'upload-file',
  212. 'import-file',
  213. ]
  214. );
  215. // Checks that the current API call is a MDB migration request.
  216. if (in_array($current_endpoint, $migration_endpoints)) {
  217. return true;
  218. }
  219. return false;
  220. }
  221. /**
  222. * @return bool
  223. */
  224. public function wpmdbc_is_wpmdb_flush_call() {
  225. if ( $this->wpmdbc_is_wpmdb_ajax_call() && in_array( $_POST['action'], array(
  226. 'wpmdb_flush',
  227. 'wpmdb_remote_flush',
  228. ) ) ) {
  229. return true;
  230. }
  231. return false;
  232. }
  233. /**
  234. * Should the current request be processed by Compatibility Mode?
  235. *
  236. * @return bool
  237. */
  238. public function wpmdbc_is_compatibility_mode_request() {
  239. if ($this->wpmdbc_is_wpmdb_rest_request()) {
  240. return true;
  241. }
  242. // Requests that shouldn't be handled by compatibility mode.
  243. if ( ! $this->wpmdbc_is_wpmdb_ajax_call() || in_array( $_POST['action'], array(
  244. 'wpmdb_get_log',
  245. 'wpmdb_maybe_collect_data',
  246. 'wpmdb_flush',
  247. 'wpmdb_remote_flush',
  248. 'wpmdb_get_themes',
  249. 'wpmdb_get_plugins',
  250. 'wpmdb_verify_connection_to_remote_site'
  251. ) ) ) {
  252. return false;
  253. }
  254. return true;
  255. }
  256. /**
  257. * Returns an array of plugin slugs to be blacklisted.
  258. *
  259. * @return array
  260. */
  261. public function wpmdbc_get_whitelist_plugins() {
  262. $whitelist_plugins = array();
  263. $wpmdb_settings = get_site_option( 'wpmdb_settings' );
  264. if ( ! empty( $wpmdb_settings['whitelist_plugins'] ) ) {
  265. $whitelist_plugins = array_flip( $wpmdb_settings['whitelist_plugins'] );
  266. }
  267. return $whitelist_plugins;
  268. }
  269. /**
  270. *
  271. * Checks if $plugin is in the $whitelisted_plugins property array
  272. *
  273. * @param $plugin
  274. * @param $whitelisted_plugins
  275. *
  276. * @return bool
  277. */
  278. public function wpmdbc_plugin_in_default_whitelist( $plugin, $whitelisted_plugins ) {
  279. if ( ! is_array( $whitelisted_plugins ) ) {
  280. return false;
  281. }
  282. if ( in_array( $plugin, $whitelisted_plugins ) ) {
  283. return true;
  284. }
  285. // strpos() check to see if the item slug is in the current $plugin name
  286. foreach ( $whitelisted_plugins as $item ) {
  287. if ( false !== strpos( $plugin, $item ) ) {
  288. return true;
  289. }
  290. }
  291. return false;
  292. }
  293. }