io = $io; } /** * Prints one box's stored code, and nothing else. * * The output is byte for byte what is stored, with no newline added, * so it can be piped back into `set` unchanged. * * ## OPTIONS * * * : Which box: head, body or footer. * * ## EXAMPLES * * # Back the head code up to a file. * $ wp adminkeep code get head > head.html * * @param array $args Location. * @param array $assoc_args Flags. * @return void */ public function get( $args, $assoc_args ) { $location = $this->location_or_halt( $args ); // Not line(): its added newline would make a get piped back into set a change. $this->io->out( HeaderFooterCode::codes()[ $location ]['code'] ); } /** * Replaces one box's code with a file's contents, or with standard input. * * The code is stored and printed exactly as given. Each box holds up * to 65,536 bytes (64 KB); anything longer is refused and nothing is * written. Empty input clears the box; if the box holds code, clearing * it asks for confirmation first, unless --yes is given. The other two * boxes are left as they are. * * The change is recorded as made by the user given with --user, or * as "WP-CLI" when there is none. A user given with --user must hold * both manage_options and unfiltered_html, as on the screen. * * ## OPTIONS * * * : Which box. head prints inside , body just after * opens, footer at the end of the page after WordPress's own footer * scripts. * * [] * : Path to a file holding the code. Leave it out, or pass -, to read * standard input. * * [--yes] * : Skip the confirmation when clearing a box that holds code. * * ## EXAMPLES * * $ wp adminkeep code set head analytics.html * $ cat gtm-noscript.html | wp adminkeep code set body * * # Clear the footer box without being asked to confirm. * $ printf '' | wp adminkeep code set footer --yes * * @param array $args Location, then an optional file path. * @param array $assoc_args Flags. * @return void */ public function set( $args, $assoc_args ) { $location = $this->location_or_halt( $args ); $path = isset( $args[1] ) ? (string) $args[1] : '-'; $user_id = get_current_user_id(); // The change is stamped with this user, and a stamp must not name someone who could not // have made the change on the screen. Without --user it is WP-CLI's own, stamped 0. if ( 0 !== $user_id && ! HeaderFooterCodeScreen::can_edit() ) { $this->io->error( sprintf( 'User %d cannot edit Header & Footer Code: it takes both manage_options and unfiltered_html. Nothing was written.', $user_id ) ); } if ( '-' === $path ) { $code = $this->io->stdin(); } else { if ( ! is_file( $path ) || ! is_readable( $path ) ) { $this->io->error( sprintf( 'Cannot read %s.', $path ) ); } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- A local file named on the command line. $code = (string) file_get_contents( $path ); } // Same normalisation the screen applies, so the size checked is the size stored. $code = str_replace( "\r\n", "\n", $code ); $valid = HeaderFooterCode::validate( array( $location => $code ) ); if ( is_wp_error( $valid ) ) { $this->io->error( $valid->get_error_message() ); } $stored = HeaderFooterCode::codes()[ $location ]['code']; if ( '' === trim( $code ) && '' !== trim( $stored ) && empty( $assoc_args['yes'] ) ) { $this->io->confirm( sprintf( 'This clears %d bytes of stored %s code. Continue?', strlen( $stored ), $location ) ); } $saved = HeaderFooterCode::save( array( $location => $code ), $user_id ); if ( is_wp_error( $saved ) ) { $this->io->error( $saved->get_error_message() ); } $label = HeaderFooterCode::location_label( $location ); $message = '' === trim( $code ) ? sprintf( '%s code cleared.', $label ) : sprintf( '%s code saved (%d bytes).', $label, strlen( $code ) ); if ( ! Settings::is_enabled( 'header_footer_code' ) ) { $message .= ' It is stored but not printed while the feature is off; turn it on with: wp adminkeep feature enable header_footer_code'; } $this->io->success( $message ); } /** * The location named first on the command line, or a halt naming the valid ones. * * Checked here rather than as a synopsis option list, so the refusal reads the same from * WP-CLI and from PHPUnit. * * @param array $args Positional arguments. * @return string */ private function location_or_halt( array $args ) { $location = isset( $args[0] ) ? (string) $args[0] : ''; if ( ! in_array( $location, HeaderFooterCode::LOCATIONS, true ) ) { $this->io->error( sprintf( 'Unknown location "%s". Valid locations: %s.', $location, implode( ', ', HeaderFooterCode::LOCATIONS ) ) ); } return $location; } }