Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
18.00% |
9 / 50 |
|
50.00% |
3 / 6 |
CRAP | |
0.00% |
0 / 1 |
| Import | |
16.67% |
8 / 48 |
|
50.00% |
3 / 6 |
357.33 | |
0.00% |
0 / 1 |
| name | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| init_listeners | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
| set_defaults | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| sync_import_action | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
72 | |||
| get_importer_name | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| get_calling_importer_class | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
132 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * Import sync module. |
| 4 | * |
| 5 | * @package automattic/jetpack-sync |
| 6 | */ |
| 7 | |
| 8 | namespace Automattic\Jetpack\Sync\Modules; |
| 9 | |
| 10 | use Automattic\Jetpack\Sync\Settings; |
| 11 | |
| 12 | if ( ! defined( 'ABSPATH' ) ) { |
| 13 | exit( 0 ); |
| 14 | } |
| 15 | |
| 16 | /** |
| 17 | * Class to handle sync for imports. |
| 18 | */ |
| 19 | class Import extends Module { |
| 20 | |
| 21 | /** |
| 22 | * Tracks which actions have already been synced for the import |
| 23 | * to prevent the same event from being triggered a second time. |
| 24 | * |
| 25 | * @var array |
| 26 | */ |
| 27 | private $synced_actions = array(); |
| 28 | |
| 29 | /** |
| 30 | * A mapping of action types to sync action name. |
| 31 | * Keys are the name of the import action. |
| 32 | * Values are the resulting sync action. |
| 33 | * |
| 34 | * Note: import_done and import_end both intentionally map to |
| 35 | * jetpack_sync_import_end, as they both track the same type of action, |
| 36 | * the successful completion of an import. Different import plugins use |
| 37 | * differently named actions, and this is an attempt to consolidate. |
| 38 | * |
| 39 | * @var array |
| 40 | */ |
| 41 | private static $import_sync_action_map = array( |
| 42 | 'import_start' => 'jetpack_sync_import_start', |
| 43 | 'import_done' => 'jetpack_sync_import_end', |
| 44 | 'import_end' => 'jetpack_sync_import_end', |
| 45 | ); |
| 46 | |
| 47 | /** |
| 48 | * Sync module name. |
| 49 | * |
| 50 | * @access public |
| 51 | * |
| 52 | * @return string |
| 53 | */ |
| 54 | public function name() { |
| 55 | return 'import'; |
| 56 | } |
| 57 | |
| 58 | /** |
| 59 | * Initialize imports action listeners. |
| 60 | * |
| 61 | * @access public |
| 62 | * |
| 63 | * @param callable $callable Action handler callable. |
| 64 | */ |
| 65 | public function init_listeners( $callable ) { |
| 66 | add_action( 'export_wp', $callable ); |
| 67 | add_action( 'jetpack_sync_import_start', $callable, 10, 2 ); |
| 68 | add_action( 'jetpack_sync_import_end', $callable, 10, 2 ); |
| 69 | |
| 70 | // WordPress. |
| 71 | add_action( 'import_start', array( $this, 'sync_import_action' ) ); |
| 72 | |
| 73 | // Movable type, RSS, Livejournal. |
| 74 | add_action( 'import_done', array( $this, 'sync_import_action' ) ); |
| 75 | |
| 76 | // WordPress, Blogger, Livejournal, woo tax rate. |
| 77 | add_action( 'import_end', array( $this, 'sync_import_action' ) ); |
| 78 | } |
| 79 | |
| 80 | /** |
| 81 | * Set module defaults. |
| 82 | * Define an empty list of synced actions for us to fill later. |
| 83 | * |
| 84 | * @access public |
| 85 | */ |
| 86 | public function set_defaults() { |
| 87 | $this->synced_actions = array(); |
| 88 | } |
| 89 | |
| 90 | /** |
| 91 | * Generic handler for import actions. |
| 92 | * |
| 93 | * @access public |
| 94 | * |
| 95 | * @param string $importer Either a string reported by the importer, the class name of the importer, or 'unknown'. |
| 96 | */ |
| 97 | public function sync_import_action( $importer ) { |
| 98 | $import_action = current_filter(); |
| 99 | // Map action to event name. |
| 100 | $sync_action = self::$import_sync_action_map[ $import_action ]; |
| 101 | |
| 102 | // Only sync each action once per import. |
| 103 | if ( array_key_exists( $sync_action, $this->synced_actions ) && $this->synced_actions[ $sync_action ] ) { |
| 104 | return; |
| 105 | } |
| 106 | |
| 107 | // Mark this action as synced. |
| 108 | $this->synced_actions[ $sync_action ] = true; |
| 109 | |
| 110 | // Prefer self-reported $importer value. |
| 111 | if ( ! $importer ) { |
| 112 | // Fall back to inferring by calling class name. |
| 113 | $importer = self::get_calling_importer_class(); |
| 114 | } |
| 115 | |
| 116 | // Get $importer from known_importers. |
| 117 | $known_importers = Settings::get_setting( 'known_importers' ); |
| 118 | if ( is_string( $importer ) && isset( $known_importers[ $importer ] ) ) { |
| 119 | $importer = $known_importers[ $importer ]; |
| 120 | } |
| 121 | |
| 122 | $importer_name = $this->get_importer_name( $importer ); |
| 123 | |
| 124 | switch ( $sync_action ) { |
| 125 | case 'jetpack_sync_import_start': |
| 126 | /** |
| 127 | * Used for syncing the start of an import |
| 128 | * |
| 129 | * @since 1.6.3 |
| 130 | * @since-jetpack 7.3.0 |
| 131 | * |
| 132 | * @module sync |
| 133 | * |
| 134 | * @param string $importer Either a string reported by the importer, the class name of the importer, or 'unknown'. |
| 135 | * @param string $importer_name The name reported by the importer, or 'Unknown Importer'. |
| 136 | */ |
| 137 | do_action( 'jetpack_sync_import_start', $importer, $importer_name ); |
| 138 | break; |
| 139 | |
| 140 | case 'jetpack_sync_import_end': |
| 141 | /** |
| 142 | * Used for syncing the end of an import |
| 143 | * |
| 144 | * @since 1.6.3 |
| 145 | * @since-jetpack 7.3.0 |
| 146 | * |
| 147 | * @module sync |
| 148 | * |
| 149 | * @param string $importer Either a string reported by the importer, the class name of the importer, or 'unknown'. |
| 150 | * @param string $importer_name The name reported by the importer, or 'Unknown Importer'. |
| 151 | */ |
| 152 | do_action( 'jetpack_sync_import_end', $importer, $importer_name ); |
| 153 | break; |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | /** |
| 158 | * Retrieve the name of the importer. |
| 159 | * |
| 160 | * @access private |
| 161 | * |
| 162 | * @param string $importer Either a string reported by the importer, the class name of the importer, or 'unknown'. |
| 163 | * @return string Name of the importer, or "Unknown Importer" if importer is unknown. |
| 164 | */ |
| 165 | private function get_importer_name( $importer ) { |
| 166 | $importers = get_importers(); |
| 167 | return isset( $importers[ $importer ] ) ? $importers[ $importer ][0] : 'Unknown Importer'; |
| 168 | } |
| 169 | |
| 170 | /** |
| 171 | * Determine the class that extends `WP_Importer` which is responsible for |
| 172 | * the current action. Designed to be used within an action handler. |
| 173 | * |
| 174 | * @access private |
| 175 | * @static |
| 176 | * |
| 177 | * @return string The name of the calling class, or 'unknown'. |
| 178 | */ |
| 179 | private static function get_calling_importer_class() { |
| 180 | // If WP_Importer doesn't exist, neither will any importer that extends it. |
| 181 | if ( ! class_exists( 'WP_Importer', false ) ) { |
| 182 | return 'unknown'; |
| 183 | } |
| 184 | |
| 185 | $action = current_filter(); |
| 186 | $backtrace = debug_backtrace( 0 ); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace |
| 187 | |
| 188 | $do_action_pos = -1; |
| 189 | $backtrace_len = count( $backtrace ); |
| 190 | for ( $i = 0; $i < $backtrace_len; $i++ ) { |
| 191 | // Find the location in the stack of the calling action. |
| 192 | if ( 'do_action' === $backtrace[ $i ]['function'] && $action === $backtrace[ $i ]['args'][0] ) { |
| 193 | $do_action_pos = $i; |
| 194 | break; |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | // If the action wasn't called, the calling class is unknown. |
| 199 | if ( -1 === $do_action_pos ) { |
| 200 | return 'unknown'; |
| 201 | } |
| 202 | |
| 203 | // Continue iterating the stack looking for a caller that extends WP_Importer. |
| 204 | for ( $i = $do_action_pos + 1; $i < $backtrace_len; $i++ ) { |
| 205 | // If there is no class on the trace, continue. |
| 206 | if ( ! isset( $backtrace[ $i ]['class'] ) ) { |
| 207 | continue; |
| 208 | } |
| 209 | |
| 210 | $class_name = $backtrace[ $i ]['class']; |
| 211 | |
| 212 | // Check if the class extends WP_Importer. |
| 213 | if ( class_exists( $class_name, false ) ) { |
| 214 | $parents = class_parents( $class_name, false ); |
| 215 | if ( $parents && in_array( 'WP_Importer', $parents, true ) ) { |
| 216 | return $class_name; |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | // If we've exhausted the stack without a match, the calling class is unknown. |
| 222 | return 'unknown'; |
| 223 | } |
| 224 | } |