* : Id of the page (any language version). * * [--format=] * : Output format. * --- * default: table * options: * - table * - json * --- * * ## EXAMPLES * * wp content-relay discover 4356 * * @param array $args Positional arguments. * @param array $assoc_args Named arguments. */ public function discover( array $args, array $assoc_args ): void { $manifest = $this->export( (int) $args[0] ); if ( 'json' === ( $assoc_args['format'] ?? 'table' ) ) { \WP_CLI::line( (string) wp_json_encode( $manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) ); return; } $rows = array(); foreach ( $manifest['objects'] as $key => $record ) { $rows[] = array( 'key' => $key, 'kind' => $record['kind'], 'role' => $record['role'], 'language' => $record['language'] ?? '', 'what' => $this->describe( $record ), 'locations' => isset( $record['locations'] ) ? count( $record['locations'] ) : '', 'via' => implode( ', ', $record['relations'] ), ); } \WP_CLI\Utils\format_items( 'table', $rows, array( 'key', 'kind', 'role', 'language', 'what', 'locations', 'via' ) ); foreach ( $manifest['requirements'] as $type => $items ) { /* translators: 1: requirement type, 2: number of required items. */ \WP_CLI::log( sprintf( __( 'Requires %1$s: %2$d', 'content-relay' ), $type, count( $items ) ) ); } foreach ( $manifest['warnings'] as $warning ) { \WP_CLI::warning( $warning ); } } /** * Writes a relay bundle — manifest.json and files/ — to a new directory in uploads/content-relay/bundles. * * The directory's path is printed. Copy it to the receiving site and pass its path to `plan` and `apply` there. * * ## OPTIONS * * * : Id of the page (any language version). * * [--porcelain] * : Print only the bundle's path. * * ## EXAMPLES * * wp content-relay bundle 4356 * * @param array $args Positional arguments. * @param array $assoc_args Named arguments. */ public function bundle( array $args, array $assoc_args ): void { $manifest = $this->export( (int) $args[0] ); $uploads = wp_get_upload_dir(); $root = untrailingslashit( (string) $uploads['basedir'] ) . '/content-relay'; $dir = $root . '/bundles/' . wp_generate_uuid4(); $copied = 0; if ( ! wp_mkdir_p( $dir . '/files' ) ) { /* translators: %s: directory path. */ \WP_CLI::error( sprintf( __( 'Cannot create %s.', 'content-relay' ), $dir ) ); } $files = array( $root . '/index.php' => " "Require all denied\n", $root . '/bundles/index.php' => " (string) wp_json_encode( $manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ), ); foreach ( $files as $path => $contents ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- Writes inside uploads from WP-CLI; WP_Filesystem may require credentials that the command cannot supply. if ( ! file_exists( $path ) && false === file_put_contents( $path, $contents ) ) { /* translators: %s: file path. */ \WP_CLI::error( sprintf( __( 'Cannot write %s.', 'content-relay' ), $path ) ); } } foreach ( $manifest['objects'] as $record ) { if ( empty( $record['file'] ) ) { continue; } $target = $dir . '/files/' . $record['file']['sha1']; if ( ! file_exists( $target ) ) { if ( ! copy( $uploads['basedir'] . '/' . $record['file']['source'], $target ) ) { /* translators: %s: file path relative to the uploads directory. */ \WP_CLI::error( sprintf( __( 'Cannot copy %s.', 'content-relay' ), $record['file']['source'] ) ); } ++$copied; } } if ( $assoc_args['porcelain'] ?? false ) { \WP_CLI::line( $dir ); return; } /* translators: 1: directory path, 2: number of objects, 3: number of files copied, 4: number of warnings. */ \WP_CLI::success( sprintf( __( 'Bundle written to %1$s: %2$d objects, %3$d files, %4$d warnings.', 'content-relay' ), $dir, count( $manifest['objects'] ), $copied, count( $manifest['warnings'] ) ) ); } /** * Exports a manifest or stops with an error. * * @param int $post_id Root post id. * @return array */ private function export( int $post_id ): array { try { return ( new Exporter( new Export_Context( Adapter_Factory::create() ) ) )->export( $post_id ); } catch ( Export_Exception $e ) { \WP_CLI::error( $e->getMessage() ); } return array(); } /** * One-line description of an object. * * @param array $record Object. */ private function describe( array $record ): string { switch ( $record['kind'] ) { case 'attachment': return isset( $record['file']['relative'] ) ? (string) $record['file']['relative'] : '(no file)'; case 'term': return $record['taxonomy'] . '/' . $record['slug']; case 'user': return (string) $record['login']; default: return $record['post_type'] . ' /' . $record['path'] . '/'; } } }