function vp_register_hooks() { global $versionPressContainer; /** @var Committer $committer */ $committer = $versionPressContainer->resolve(VersionPressServices::COMMITTER); /** @var Mirror $mirror */ $mirror = $versionPressContainer->resolve(VersionPressServices::MIRROR); /** @var DbSchemaInfo $dbSchemaInfo */ $dbSchemaInfo = $versionPressContainer->resolve(VersionPressServices::DB_SCHEMA); /** @var VpidRepository $vpidRepository */ $vpidRepository = $versionPressContainer->resolve(VersionPressServices::VPID_REPOSITORY); /** @var WpdbMirrorBridge $wpdbMirrorBridge */ $wpdbMirrorBridge = $versionPressContainer->resolve(VersionPressServices::WPDB_MIRROR_BRIDGE); /** @var \VersionPress\Database\Database $database */ $database = $versionPressContainer->resolve(VersionPressServices::DATABASE); /** @var ActionsInfoProvider $actionsInfoProvider */ $actionsInfoProvider = $versionPressContainer->resolve(VersionPressServices::ACTIONSINFO_PROVIDER_ACTIVE_PLUGINS); if (!function_exists('get_plugins')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $plugins = wp_get_active_and_valid_plugins(); foreach ($plugins as $pluginFile) { $pluginDir = dirname($pluginFile); $hooksFile = $pluginDir . '/.versionpress/hooks.php'; if (file_exists($hooksFile)) { require_once $hooksFile; } } add_filter('update_feedback', function () { touch(ABSPATH . 'versionpress.maintenance'); }); WordPressMissingFunctions::pipeAction('_core_updated_successfully', 'vp_wordpress_updated'); add_action('activated_plugin', function ($pluginFile) { $plugins = get_plugins(); $pluginName = $plugins[$pluginFile]['Name']; do_action('vp_plugin_changed', 'activate', $pluginFile, $pluginName); }); add_action('deactivated_plugin', function ($pluginFile) { $plugins = get_plugins(); $pluginName = $plugins[$pluginFile]['Name']; do_action('vp_plugin_changed', 'deactivate', $pluginFile, $pluginName); }); add_action('upgrader_process_complete', function ($upgrader, $hook_extra) { if ($hook_extra['type'] === 'theme') { $themes = isset($hook_extra['bulk']) && $hook_extra['bulk'] === true ? $hook_extra['themes'] : [$upgrader->result['destination_name']]; foreach ($themes as $stylesheet) { $themeName = wp_get_theme($stylesheet)->get('Name'); if ($themeName === $stylesheet && isset($upgrader->skin->api, $upgrader->skin->api->name)) { $themeName = $upgrader->skin->api->name; } // action can be "install" or "update", see WP_Upgrader and search for `'hook_extra' =>` $action = $hook_extra['action']; do_action('vp_theme_changed', $action, $stylesheet, $themeName); } } if (!($hook_extra['type'] === 'plugin' && $hook_extra['action'] === 'update')) { return; // handled by different hook } if (isset($hook_extra['bulk']) && $hook_extra['bulk'] === true) { $pluginFiles = $hook_extra['plugins']; } else { $pluginFiles = [$hook_extra['plugin']]; } $plugins = get_plugins(); foreach ($pluginFiles as $pluginFile) { $pluginName = $plugins[$pluginFile]['Name']; do_action('vp_plugin_changed', 'update', $pluginFile, $pluginName); } }, 10, 2); add_filter('upgrader_pre_install', function ($_, $hook_extra) { if (!(isset($hook_extra['type']) && $hook_extra['type'] === 'plugin' && $hook_extra['action'] === 'install')) { return; } $pluginsBeforeInstallation = get_plugins(); $postInstallHook = function ($_, $hook_extra) use($pluginsBeforeInstallation, &$postInstallHook) { if (!($hook_extra['type'] === 'plugin' && $hook_extra['action'] === 'install')) { return; } wp_cache_delete('plugins', 'plugins'); $pluginsAfterInstallation = get_plugins(); $installedPlugins = array_diff_key($pluginsAfterInstallation, $pluginsBeforeInstallation); foreach ($installedPlugins as $pluginFile => $plugin) { do_action('vp_plugin_changed', 'install', $pluginFile, $plugin['Name']); } remove_filter('upgrader_post_install', $postInstallHook); }; add_filter('upgrader_post_install', $postInstallHook, 10, 2); }, 10, 2); add_filter('upgrader_pre_download', function ($reply, $_, $upgrader) use($committer) { if (!isset($upgrader->skin->language_update)) { return $reply; } $languages = get_available_languages(); $postInstallHook = function ($_, $hook_extra) use($committer, $languages, &$postInstallHook) { if (!isset($hook_extra['language_update_type'])) { return; } $type = $hook_extra['language_update_type']; $languageCode = $hook_extra['language_update']->language; $name = $type === "core" ? null : $hook_extra['language_update']->slug; $action = in_array($languageCode, $languages) ? "update" : "install"; do_action('vp_translation_changed', $action, $languageCode, $type, $name); remove_filter('upgrader_post_install', $postInstallHook); }; add_filter('upgrader_post_install', $postInstallHook, 10, 2); return false; }, 10, 3); add_action('switch_theme', function () use($committer) { if (defined('WP_CLI') && WP_CLI) { wp_remote_get(admin_url()); // } else { $committer->disableCommit(); // the change will be committed on next load } }); add_action('after_switch_theme', function () use($committer) { $theme = wp_get_theme(); $stylesheet = $theme->get_stylesheet(); $themeName = $theme->get('Name'); do_action('vp_theme_changed', 'switch', $stylesheet, $themeName); }); function _vp_get_language_name_by_code($code) { require_once ABSPATH . 'wp-admin/includes/translation-install.php'; $translations = wp_get_available_translations(); return isset($translations[$code]) ? $translations[$code]['native_name'] : 'English (United States)'; } add_action('add_option_WPLANG', function ($option, $value) use($committer) { $defaultLanguage = defined('WPLANG') ? WPLANG : ''; if ($value === $defaultLanguage) { return; // It's just submitted settings form without changing language } do_action('vp_translation_changed', 'activate', $value); }, 10, 2); add_action('update_option_WPLANG', function ($oldValue, $newValue) use($committer) { do_action('vp_translation_changed', 'activate', $newValue); }, 10, 2); add_action('wp_update_nav_menu_item', function ($menu_id, $menu_item_db_id) use($committer) { $key = 'menu-item-' . $menu_item_db_id; if (defined('DOING_AJAX') && DOING_AJAX && isset($_POST['action']) && $_POST['action'] === 'add-menu-item') { $committer->postponeCommit($key); $committer->commit(); } elseif (isset($_POST['action']) && $_POST['action'] === 'update') { $committer->usePostponedChangeInfos($key); } }, 10, 2); add_action('pre_delete_term', function ($termId, $taxonomy) use($committer, $vpidRepository, $dbSchemaInfo, $actionsInfoProvider) { $termVpid = $vpidRepository->getVpidForEntity('term', $termId); $term = get_term($termId, $taxonomy); $termEntityInfo = $dbSchemaInfo->getEntityInfo('term'); $actionsInfo = $actionsInfoProvider->getActionsInfo('term'); $changeInfo = new EntityChangeInfo($termEntityInfo, $actionsInfo, 'delete', $termVpid, ['VP-Term-Name' => $term->name, 'VP-Term-Taxonomy' => $taxonomy]); $committer->forceChangeInfo($changeInfo); }, 10, 2); add_filter('wp_save_image_editor_file', function ($saved, $filename, $image, $mime_type, $post_id) use($vpidRepository, $committer, $dbSchemaInfo, $actionsInfoProvider) { $vpid = $vpidRepository->getVpidForEntity('post', $post_id); $post = get_post($post_id); $actionsInfo = $actionsInfoProvider->getActionsInfo('post'); $changeInfo = new EntityChangeInfo($dbSchemaInfo->getEntityInfo('post'), $actionsInfo, 'edit', $vpid, ['VP-Post-Type' => $post->post_type, 'VP-Post-Title' => $post->post_title]); $committer->forceChangeInfo($changeInfo); }, 10, 5); add_filter('plugin_install_action_links', function ($links, $plugin) { $compatibility = CompatibilityChecker::testCompatibilityBySlug($plugin['slug']); if ($compatibility === CompatibilityResult::COMPATIBLE) { $cssClass = 'vp-compatible'; $compatibilityAdjective = 'Compatible'; } elseif ($compatibility === CompatibilityResult::INCOMPATIBLE) { $cssClass = 'vp-incompatible'; // @codingStandardsIgnoreLine $compatibilityAdjective = '<a href="http://docs.versionpress.net/en/integrations/plugins" target="_blank" title="This plugin is not compatible with VersionPress. These plugins will not work correctly when used together.">Incompatible</a>'; } else { $cssClass = 'vp-untested'; // @codingStandardsIgnoreLine $compatibilityAdjective = '<a href="http://docs.versionpress.net/en/integrations/plugins" target="_blank" title="This plugin was not yet tested with VersionPress. Some functionality may not work as intended.">Untested</a>'; } // @codingStandardsIgnoreLine $compatibilityNotice = '<span class="vp-compatibility %s" data-plugin-name="%s"><strong>%s</strong> with VersionPress</span>'; $links[] = sprintf($compatibilityNotice, $cssClass, $plugin['name'], $compatibilityAdjective); return $links; }, 10, 2); add_filter('plugin_row_meta', function ($plugin_meta, $plugin_file, $plugin_data, $status) { if ($status === "dropins") { return $plugin_meta; } $compatibility = CompatibilityChecker::testCompatibilityByPluginFile($plugin_file); if ($compatibility === CompatibilityResult::COMPATIBLE) { $cssClass = 'vp-compatible'; $compatibilityAdjective = 'Compatible'; } elseif ($compatibility === CompatibilityResult::INCOMPATIBLE) { $cssClass = 'vp-incompatible'; // @codingStandardsIgnoreLine $compatibilityAdjective = '<a href="http://docs.versionpress.net/en/integrations/plugins" target="_blank" title="This plugin is not compatible with VersionPress. These plugins will not work correctly when used together.">Incompatible</a>'; } elseif ($compatibility === CompatibilityResult::UNTESTED) { $cssClass = 'vp-untested'; // @codingStandardsIgnoreLine $compatibilityAdjective = '<a href="http://docs.versionpress.net/en/integrations/plugins" target="_blank" title="This plugin was not yet tested with VersionPress. Some functionality may not work as intended.">Untested</a>'; } else { return $plugin_meta; } // @codingStandardsIgnoreLine $compatibilityNotice = '<span class="vp-compatibility %s" data-plugin-name="%s"><strong>%s</strong> with VersionPress</span>'; $plugin_meta[] = sprintf($compatibilityNotice, $cssClass, $plugin_data['Name'], $compatibilityAdjective); return $plugin_meta; }, 10, 4); add_filter('plugin_action_links', function ($actions, $plugin_file) { $compatibility = CompatibilityChecker::testCompatibilityByPluginFile($plugin_file); if (isset($actions['activate'])) { if ($compatibility === CompatibilityResult::UNTESTED) { $actions['activate'] = "<span class=\"vp-plugin-list vp-untested\">{$actions['activate']}</span>"; } elseif ($compatibility === CompatibilityResult::INCOMPATIBLE) { $actions['activate'] = "<span class=\"vp-plugin-list vp-incompatible\">{$actions['activate']}</span>"; } } return $actions; }, 10, 2); add_action('vp_revert', function ($modifiedFiles) { // We have to flush the rewrite rules in the next request, because // in the current one the changed rewrite rules are not yet effective. set_transient('vp_flush_rewrite_rules', 1); vp_flush_regenerable_options(); // Update composer dependencies if (array_search('composer.lock', $modifiedFiles) || array_search('composer.json', $modifiedFiles)) { putenv('COMPOSER_HOME=' . VP_PROJECT_ROOT . '/vendor/bin/composer'); $originalCwd = getcwd(); chdir(VP_PROJECT_ROOT); $input = new \Symfony\Component\Console\Input\ArrayInput(['command' => 'install']); $output = new \Symfony\Component\Console\Output\NullOutput(); $application = new \Composer\Console\Application(); $application->setAutoExit(false); // prevent `$application->run` method from exitting the script $application->run($input, $output); $application->getComposer(); chdir($originalCwd); } }); add_action('pre_delete_term', function ($term, $taxonomy) use($database, $wpdbMirrorBridge) { if (!is_taxonomy_hierarchical($taxonomy)) { return; } $term = get_term($term, $taxonomy); if (is_wp_error($term)) { return; } $wpdbMirrorBridge->update($database->term_taxonomy, ['parent' => $term->parent], ['parent' => $term->term_id]); }, 10, 2); add_action('before_delete_post', function ($postId) use($database, $wpdbMirrorBridge) { // Fixing bug in WP (#34803) and WP-CLI (#2246); $post = get_post($postId); if (!is_wp_error($post) && $post->post_type === 'nav_menu_item') { $newParent = get_post_meta($post->ID, '_menu_item_menu_item_parent', true); $wpdbMirrorBridge->update($database->postmeta, ['meta_value' => $newParent], ['meta_key' => '_menu_item_menu_item_parent', 'meta_value' => $post->ID]); $database->update($database->postmeta, ['meta_value' => $newParent], ['meta_key' => '_menu_item_menu_item_parent', 'meta_value' => $post->ID]); } }); //---------------------------------------- // URL and WP-CLI "hooks" //---------------------------------------- $requestDetector = new \VersionPress\Utils\RequestDetector(); if ($requestDetector->isThemeDeleteRequest()) { $themeIds = $requestDetector->getThemeStylesheets(); foreach ($themeIds as $stylesheet) { $themeName = wp_get_theme($stylesheet)->get('Name'); do_action('vp_theme_changed', 'delete', $stylesheet, $themeName); } } if ($requestDetector->isPluginDeleteRequest()) { $pluginNames = $requestDetector->getPluginNames(); $plugins = get_plugins(); foreach ($pluginNames as $plugin) { do_action('vp_plugin_changed', 'delete', $plugin, $plugins[$plugin]['Name']); } } if ($requestDetector->isCoreLanguageUninstallRequest()) { $languageCode = $requestDetector->getLanguageCode(); do_action('vp_translation_changed', 'uninstall', $languageCode); } if (basename($_SERVER['PHP_SELF']) === 'theme-editor.php' && isset($_GET['updated']) && $_GET['updated'] === 'true') { $stylesheet = $_GET['theme']; $themeName = wp_get_theme($stylesheet)->get('Name'); do_action('vp_theme_changed', 'edit', $stylesheet, $themeName); } if (basename($_SERVER['PHP_SELF']) === 'plugin-editor.php' && (isset($_POST['action']) && $_POST['action'] === 'update' || isset($_GET['liveupdate']))) { $committer->disableCommit(); } if (basename($_SERVER['PHP_SELF']) === 'plugin-editor.php' && isset($_GET['a']) && $_GET['a'] === 'te') { if (!function_exists('get_plugins')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $editedFile = $_GET['file']; $editedFilePathParts = preg_split("~[/\\\\]~", $editedFile); $plugins = get_plugins(); $pluginNames = array_keys($plugins); $bestRank = 0; $bestMatch = ""; foreach ($pluginNames as $plugin) { $rank = 0; $pluginPathParts = preg_split("~[/\\\\]~", $plugin); $maxEqualParts = min(count($editedFilePathParts), count($pluginPathParts)); for ($part = 0; $part < $maxEqualParts; $part++) { if ($editedFilePathParts[$part] !== $pluginPathParts[$part]) { break; } $rank += 1; } if ($rank > $bestRank) { $bestRank = $rank; $bestMatch = $plugin; } } do_action('vp_plugin_changed', 'edit', $bestMatch, $plugins[$bestMatch]['Name']); } add_filter('cron_schedules', function ($schedules) use($dbSchemaInfo) { $intervals = $dbSchemaInfo->getIntervalsForFrequentlyWrittenEntities(); foreach ($intervals as $interval) { if (isset($schedules[$interval])) { continue; } $seconds = strtotime($interval, 0); $schedules[$interval] = ['interval' => $seconds, 'display' => $interval]; } return $schedules; }); $r = $dbSchemaInfo->getRulesForFrequentlyWrittenEntities(); $groupedByInterval = []; foreach ($r as $entityName => $rules) { foreach ($rules as $rule) { $groupedByInterval[$rule['interval']][$entityName][] = $rule; } } foreach ($groupedByInterval as $interval => $allRulesInInterval) { $actionName = "vp_commit_frequently_written_entities_{$interval}"; if (!wp_next_scheduled($actionName)) { wp_schedule_event(time(), $interval, $actionName); } add_action($actionName, function () use($allRulesInInterval) { vp_save_frequently_written_entities($allRulesInInterval); }); } if (!function_exists('get_plugins')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } register_shutdown_function([$committer, 'commit']); }
function vp_register_hooks() { global $wpdb, $versionPressContainer; /** @var Committer $committer */ $committer = $versionPressContainer->resolve(VersionPressServices::COMMITTER); /** @var Mirror $mirror */ $mirror = $versionPressContainer->resolve(VersionPressServices::MIRROR); /** @var DbSchemaInfo $dbSchemaInfo */ $dbSchemaInfo = $versionPressContainer->resolve(VersionPressServices::DB_SCHEMA); /** @var VpidRepository $vpidRepository */ $vpidRepository = $versionPressContainer->resolve(VersionPressServices::VPID_REPOSITORY); /** @var WpdbMirrorBridge $wpdbMirrorBridge */ $wpdbMirrorBridge = $versionPressContainer->resolve(VersionPressServices::WPDB_MIRROR_BRIDGE); /** * Hook for saving taxonomies into files * WordPress creates plain INSERT query and executes it using wpdb::query method instead of wpdb::insert. * It's too difficult to parse every INSERT query, that's why the WordPress hook is used. */ add_action('save_post', createUpdatePostTermsHook($mirror, $vpidRepository)); add_filter('update_feedback', function () { touch(ABSPATH . 'versionpress.maintenance'); }); add_action('_core_updated_successfully', function () use($committer, $mirror) { require ABSPATH . 'wp-includes/version.php'; // load constants (like $wp_version) /** @var string $wp_version */ $changeInfo = new WordPressUpdateChangeInfo($wp_version); $committer->forceChangeInfo($changeInfo); $mirror->save('option', array('option_name' => 'db_version', 'option_value' => get_option('db_version'))); // We have to re-save the option because WP upgrader uses $wpdb->query() if (!WpdbReplacer::isReplaced()) { WpdbReplacer::replaceMethods(); } }); add_action('activated_plugin', function ($pluginName) use($committer) { $committer->forceChangeInfo(new PluginChangeInfo($pluginName, 'activate')); }); add_action('deactivated_plugin', function ($pluginName) use($committer) { $committer->forceChangeInfo(new PluginChangeInfo($pluginName, 'deactivate')); }); add_action('upgrader_process_complete', function ($upgrader, $hook_extra) use($committer) { if ($hook_extra['type'] === 'theme') { $themes = isset($hook_extra['bulk']) && $hook_extra['bulk'] === true ? $hook_extra['themes'] : array($upgrader->result['destination_name']); foreach ($themes as $theme) { $themeName = wp_get_theme($theme)->get('Name'); if ($themeName === $theme && isset($upgrader->skin->api, $upgrader->skin->api->name)) { $themeName = $upgrader->skin->api->name; } $action = $hook_extra['action']; // can be "install" or "update", see WP_Upgrader and search for `'hook_extra' =>` $committer->forceChangeInfo(new ThemeChangeInfo($theme, $action, $themeName)); } } if (!($hook_extra['type'] === 'plugin' && $hook_extra['action'] === 'update')) { return; } // handled by different hook if (isset($hook_extra['bulk']) && $hook_extra['bulk'] === true) { $plugins = $hook_extra['plugins']; } else { $plugins = array($hook_extra['plugin']); } foreach ($plugins as $plugin) { $committer->forceChangeInfo(new PluginChangeInfo($plugin, 'update')); } }, 10, 2); add_action('added_option', function ($name) use($wpdb, $mirror) { $option = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}options WHERE option_name='{$name}'", ARRAY_A); $mirror->save("option", $option); }); add_filter('upgrader_pre_install', function ($_, $hook_extra) use($committer) { if (!(isset($hook_extra['type']) && $hook_extra['type'] === 'plugin' && $hook_extra['action'] === 'install')) { return; } $pluginsBeforeInstallation = get_plugins(); $postInstallHook = function ($_, $hook_extra) use($pluginsBeforeInstallation, $committer, &$postInstallHook) { if (!($hook_extra['type'] === 'plugin' && $hook_extra['action'] === 'install')) { return; } wp_cache_delete('plugins', 'plugins'); $pluginsAfterInstallation = get_plugins(); $installedPlugin = array_diff_key($pluginsAfterInstallation, $pluginsBeforeInstallation); reset($installedPlugin); $pluginName = key($installedPlugin); $committer->forceChangeInfo(new PluginChangeInfo($pluginName, 'install')); remove_filter('upgrader_post_install', $postInstallHook); }; add_filter('upgrader_post_install', $postInstallHook, 10, 2); }, 10, 2); add_filter('upgrader_pre_download', function ($reply, $_, $upgrader) use($committer) { if (!isset($upgrader->skin->language_update)) { return $reply; } $languages = get_available_languages(); $postInstallHook = function ($_, $hook_extra) use($committer, $languages, &$postInstallHook) { if (!isset($hook_extra['language_update_type'])) { return; } $translations = wp_get_available_translations(); $type = $hook_extra['language_update_type']; $languageCode = $hook_extra['language_update']->language; $languageName = isset($translations[$languageCode]) ? $translations[$languageCode]['native_name'] : 'English (United States)'; $name = $type === "core" ? null : $hook_extra['language_update']->slug; $action = in_array($languageCode, $languages) ? "update" : "install"; $committer->forceChangeInfo(new TranslationChangeInfo($action, $languageCode, $languageName, $type, $name)); remove_filter('upgrader_post_install', $postInstallHook); }; add_filter('upgrader_post_install', $postInstallHook, 10, 2); return false; }, 10, 3); add_action('switch_theme', function () use($committer) { if (defined('WP_CLI') && WP_CLI) { file_get_contents(admin_url()); // } else { $committer->disableCommit(); // the change will be committed on next load } }); add_action('after_switch_theme', function () use($committer) { $theme = wp_get_theme(); $stylesheet = $theme->get_stylesheet(); $themeName = $theme->get('Name'); $committer->forceChangeInfo(new ThemeChangeInfo($stylesheet, 'switch', $themeName)); }); add_action('customize_save_after', function ($customizeManager) use($committer) { /** @var WP_Customize_Manager $customizeManager */ $stylesheet = $customizeManager->theme()->get_stylesheet(); $committer->forceChangeInfo(new ThemeChangeInfo($stylesheet, 'customize')); register_shutdown_function(function () { wp_remote_get(admin_url("admin.php")); }); }); add_action('untrashed_post_comments', function ($postId) use($wpdb, $dbSchemaInfo, $wpdbMirrorBridge) { $commentsTable = $dbSchemaInfo->getPrefixedTableName("comment"); $commentStatusSql = "select comment_ID, comment_approved from {$commentsTable} where comment_post_ID = {$postId}"; $comments = $wpdb->get_results($commentStatusSql, ARRAY_A); foreach ($comments as $comment) { $wpdbMirrorBridge->update($commentsTable, array("comment_approved" => $comment["comment_approved"]), array("comment_ID" => $comment["comment_ID"])); } }); add_action('delete_post_meta', function ($metaIds) use($wpdbMirrorBridge, $dbSchemaInfo) { $idColumnName = $dbSchemaInfo->getEntityInfo("postmeta")->idColumnName; foreach ($metaIds as $metaId) { $wpdbMirrorBridge->delete($dbSchemaInfo->getPrefixedTableName("postmeta"), array($idColumnName => $metaId)); } }); add_action('delete_user_meta', function ($metaIds) use($wpdbMirrorBridge, $dbSchemaInfo) { $idColumnName = $dbSchemaInfo->getEntityInfo("usermeta")->idColumnName; foreach ($metaIds as $metaId) { $wpdbMirrorBridge->delete($dbSchemaInfo->getPrefixedTableName("usermeta"), array($idColumnName => $metaId)); } }); add_action('wp_ajax_save-widget', function () use($committer) { if (defined('DOING_AJAX') && DOING_AJAX && isset($_POST['delete_widget']) && $_POST['delete_widget']) { $committer->postponeCommit('widgets'); } }, 0); // zero because the default WP action with priority 1 calls wp_die() function _vp_get_language_name_by_code($code) { $translations = wp_get_available_translations(); return isset($translations[$code]) ? $translations[$code]['native_name'] : 'English (United States)'; } add_action('add_option_WPLANG', function ($option, $value) use($committer) { $defaultLanguage = defined('WPLANG') ? WPLANG : ''; if ($value === $defaultLanguage) { return; // It's just submitted settings form without changing language } $languageName = _vp_get_language_name_by_code($value); $committer->forceChangeInfo(new TranslationChangeInfo("activate", $value, $languageName)); }, 10, 2); add_action('update_option_WPLANG', function ($oldValue, $newValue) use($committer) { $languageName = _vp_get_language_name_by_code($newValue); $committer->forceChangeInfo(new TranslationChangeInfo("activate", $newValue, $languageName)); }, 10, 2); add_action('wp_update_nav_menu_item', function ($menu_id, $menu_item_db_id) use($committer) { $key = 'menu-item-' . $menu_item_db_id; if (defined('DOING_AJAX') && DOING_AJAX && isset($_POST['action']) && $_POST['action'] === 'add-menu-item') { $committer->postponeCommit($key); $committer->commit(); } elseif (isset($_POST['action']) && $_POST['action'] === 'update') { $committer->usePostponedChangeInfos($key); } if (!defined('DOING_AJAX')) { global $versionPressContainer; /** @var Mirror $mirror */ $mirror = $versionPressContainer->resolve(VersionPressServices::MIRROR); $vpidRepository = $versionPressContainer->resolve(VersionPressServices::VPID_REPOSITORY); $func = createUpdatePostTermsHook($mirror, $vpidRepository); $func($menu_item_db_id); } }, 10, 2); add_action('pre_delete_term', function ($termId, $taxonomy) use($committer, $vpidRepository) { $termVpid = $vpidRepository->getVpidForEntity('term', $termId); $term = get_term($termId, $taxonomy); $committer->forceChangeInfo(new \VersionPress\ChangeInfos\TermChangeInfo('delete', $termVpid, $term->name, $taxonomy)); }, 10, 2); add_action('set_object_terms', createUpdatePostTermsHook($mirror, $vpidRepository)); add_filter('plugin_install_action_links', function ($links, $plugin) { $compatibility = CompatibilityChecker::testCompatibilityBySlug($plugin['slug']); if ($compatibility === CompatibilityResult::COMPATIBLE) { $cssClass = 'vp-compatible'; $compatibilityAdjective = 'Compatible'; } elseif ($compatibility === CompatibilityResult::INCOMPATIBLE) { $cssClass = 'vp-incompatible'; $compatibilityAdjective = '<a href="http://docs.versionpress.net/en/integrations/plugins" target="_blank" title="This plugin is not compatible with VersionPress. These plugins will not work correctly when used together.">Incompatible</a>'; } else { $cssClass = 'vp-untested'; $compatibilityAdjective = '<a href="http://docs.versionpress.net/en/integrations/plugins" target="_blank" title="This plugin was not yet tested with VersionPress. Some functionality may not work as intended.">Untested</a>'; } $compatibilityNotice = '<span class="vp-compatibility %s" data-plugin-name="%s"><strong>%s</strong> with VersionPress</span>'; $links[] = sprintf($compatibilityNotice, $cssClass, $plugin['name'], $compatibilityAdjective); return $links; }, 10, 2); add_filter('plugin_row_meta', function ($plugin_meta, $plugin_file, $plugin_data, $status) { if ($status === "dropins") { return $plugin_meta; } $compatibility = CompatibilityChecker::testCompatibilityByPluginFile($plugin_file); if ($compatibility === CompatibilityResult::COMPATIBLE) { $cssClass = 'vp-compatible'; $compatibilityAdjective = 'Compatible'; } elseif ($compatibility === CompatibilityResult::INCOMPATIBLE) { $cssClass = 'vp-incompatible'; $compatibilityAdjective = '<a href="http://docs.versionpress.net/en/integrations/plugins" target="_blank" title="This plugin is not compatible with VersionPress. These plugins will not work correctly when used together.">Incompatible</a>'; } elseif ($compatibility === CompatibilityResult::UNTESTED) { $cssClass = 'vp-untested'; $compatibilityAdjective = '<a href="http://docs.versionpress.net/en/integrations/plugins" target="_blank" title="This plugin was not yet tested with VersionPress. Some functionality may not work as intended.">Untested</a>'; } else { return $plugin_meta; } $compatibilityNotice = '<span class="vp-compatibility %s" data-plugin-name="%s"><strong>%s</strong> with VersionPress</span>'; $plugin_meta[] = sprintf($compatibilityNotice, $cssClass, $plugin_data['Name'], $compatibilityAdjective); return $plugin_meta; }, 10, 4); add_filter('plugin_action_links', function ($actions, $plugin_file) { $compatibility = CompatibilityChecker::testCompatibilityByPluginFile($plugin_file); if (isset($actions['activate'])) { if ($compatibility === CompatibilityResult::UNTESTED) { $actions['activate'] = "<span class=\"vp-plugin-list vp-untested\">{$actions['activate']}</span>"; } elseif ($compatibility === CompatibilityResult::INCOMPATIBLE) { $actions['activate'] = "<span class=\"vp-plugin-list vp-incompatible\">{$actions['activate']}</span>"; } } return $actions; }, 10, 2); add_action('vp_revert', function () { // We have to flush the rewrite rules in the next request, because // in the current one the changed rewrite rules are not yet effective. set_transient('vp_flush_rewrite_rules', 1); vp_flush_regenerable_options(); }); add_action('pre_delete_term', function ($term, $taxonomy) use($wpdb, $wpdbMirrorBridge) { if (!is_taxonomy_hierarchical($taxonomy)) { return; } $term = get_term($term, $taxonomy); if (is_wp_error($term)) { return; } $wpdbMirrorBridge->update($wpdb->term_taxonomy, array('parent' => $term->parent), array('parent' => $term->term_id)); }, 10, 2); add_action('before_delete_post', function ($postId) use($wpdb) { // Fixing bug in WP (#34803) and WP-CLI (#2246) $post = get_post($postId); if (!is_wp_error($post) && $post->post_type === 'nav_menu_item') { \Tracy\Debugger::log('Deleting menu item ' . $post->ID); $newParent = get_post_meta($post->ID, '_menu_item_menu_item_parent', true); $wpdb->update($wpdb->postmeta, array('meta_value' => $newParent), array('meta_key' => '_menu_item_menu_item_parent', 'meta_value' => $post->ID)); } }); //---------------------------------------- // URL and WP-CLI "hooks" //---------------------------------------- $requestDetector = new \VersionPress\Utils\RequestDetector(); if (defined('DOING_AJAX') && DOING_AJAX && isset($_REQUEST['action']) && $_REQUEST['action'] === 'widgets-order') { $committer->usePostponedChangeInfos('widgets'); } if ($requestDetector->isThemeDeleteRequest()) { $themeIds = $requestDetector->getThemeStylesheets(); foreach ($themeIds as $themeId) { $committer->forceChangeInfo(new ThemeChangeInfo($themeId, 'delete')); } } if ($requestDetector->isPluginDeleteRequest()) { $plugins = $requestDetector->getPluginNames(); foreach ($plugins as $plugin) { $committer->forceChangeInfo(new PluginChangeInfo($plugin, 'delete')); } } if ($requestDetector->isCoreLanguageUninstallRequest()) { $languageCode = $requestDetector->getLanguageCode(); $translations = wp_get_available_translations(); $languageName = isset($translations[$languageCode]) ? $translations[$languageCode]['native_name'] : 'English (United States)'; $committer->forceChangeInfo(new TranslationChangeInfo('uninstall', $languageCode, $languageName, 'core')); } if (basename($_SERVER['PHP_SELF']) === 'theme-editor.php' && isset($_GET['updated']) && $_GET['updated'] === 'true') { $committer->forceChangeInfo(new ThemeChangeInfo($_GET['theme'], 'edit')); } if (basename($_SERVER['PHP_SELF']) === 'plugin-editor.php' && (isset($_POST['action']) && $_POST['action'] === 'update' || isset($_GET['liveupdate']))) { $committer->disableCommit(); } if (basename($_SERVER['PHP_SELF']) === 'plugin-editor.php' && isset($_GET['a']) && $_GET['a'] === 'te') { if (!function_exists('get_plugins')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $editedFile = $_GET['file']; $editedFilePathParts = preg_split("~[/\\\\]~", $editedFile); $plugins = array_keys(get_plugins()); $bestRank = 0; $bestMatch = ""; foreach ($plugins as $plugin) { $rank = 0; $pluginPathParts = preg_split("~[/\\\\]~", $plugin); $maxEqualParts = min(count($editedFilePathParts), count($pluginPathParts)); for ($part = 0; $part < $maxEqualParts; $part++) { if ($editedFilePathParts[$part] !== $pluginPathParts[$part]) { break; } $rank += 1; } if ($rank > $bestRank) { $bestRank = $rank; $bestMatch = $plugin; } } $committer->forceChangeInfo(new PluginChangeInfo($bestMatch, 'edit')); } register_shutdown_function(array($committer, 'commit')); }