esc_url_raw( rest_url( 'sirius-press/v1/export' ) ), 'nonce' => wp_create_nonce( 'wp_rest' ), 'gateway' => SP_Settings::gateway(), 'name' => SP_Settings::name(), 'prefix' => SP_Settings::prefix(), 'path' => SP_Settings::derivation_path(), ) ); add_action( 'admin_footer', array( 'SPA_Login', 'print_config' ) ); } // -------------------------------------------------- manual-signing routes public static function register_routes() { $can_manage = function () { return current_user_can( 'manage_options' ); }; register_rest_route( 'sirius-press/v1', '/export/next', array( 'methods' => WP_REST_Server::READABLE, 'permission_callback' => $can_manage, 'callback' => array( __CLASS__, 'rest_next' ), ) ); register_rest_route( 'sirius-press/v1', '/export/ack', array( 'methods' => WP_REST_Server::CREATABLE, 'permission_callback' => $can_manage, 'callback' => array( __CLASS__, 'rest_ack' ), ) ); } /** * Build the next few queued files and hand them to the browser. * * Bodies come back base64-encoded because a queued file may be a PNG, and * JSON has no way to carry arbitrary bytes otherwise. */ public static function rest_next( WP_REST_Request $request ) { $limit = max( 1, min( 5, (int) $request->get_param( 'limit' ) ?: 3 ) ); $items = array(); foreach ( SPE_Queue::claim( $limit ) as $row ) { $body = SPE_Runner::build( $row ); if ( is_wp_error( $body ) ) { SPE_Queue::mark_failed( $row->id, $body->get_error_message() ); continue; } $hash = hash( 'sha256', $body ); if ( '' !== $row->content_hash && hash_equals( $row->content_hash, $hash ) ) { SPE_Queue::mark_done( $row->id, $hash ); continue; } $items[] = array( 'id' => (int) $row->id, 'path' => $row->path, 'mime' => SP_Gateway::mime_for( $row->path ), 'sha256' => $hash, 'body_b64' => base64_encode( $body ), ); } return rest_ensure_response( array( 'items' => $items, 'left' => SPE_Queue::counts()[ SPE_Queue::STATUS_PENDING ], ) ); } /** The browser reports how an upload went. */ public static function rest_ack( WP_REST_Request $request ) { $id = (int) $request->get_param( 'id' ); $hash = (string) $request->get_param( 'sha256' ); $error = (string) $request->get_param( 'error' ); if ( '' !== $error ) { SPE_Queue::mark_failed( $id, $error ); return rest_ensure_response( array( 'ok' => false ) ); } if ( ! preg_match( '/^[a-f0-9]{64}$/', $hash ) ) { return new WP_Error( 'sirius_bad_hash', __( 'Bad hash.', 'sirius-press' ), array( 'status' => 400 ) ); } SPE_Queue::mark_done( $id, $hash ); return rest_ensure_response( array( 'ok' => true ) ); } // ------------------------------------------------------------------ page public static function render() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You are not allowed to publish this site.', 'sirius-press' ) ); } $notes = array(); if ( isset( $_POST['sirius_export_action'] ) && check_admin_referer( 'sirius_export' ) ) { $action = sanitize_key( wp_unslash( $_POST['sirius_export_action'] ) ); if ( 'full' === $action ) { $n = SPE_Runner::queue_full_site(); $notes[] = sprintf( /* translators: %d: number of pages queued. */ _n( '%d page queued for export.', '%d pages queued for export.', $n, 'sirius-press' ), $n ); } elseif ( 'retry' === $action ) { $n = SPE_Queue::retry_failed(); $notes[] = sprintf( /* translators: %d: number of failed exports re-queued. */ _n( '%d failed export queued again.', '%d failed exports queued again.', $n, 'sirius-press' ), $n ); } elseif ( 'run' === $action ) { $r = SPE_Runner::run_batch( 20 ); $notes[] = sprintf( /* translators: 1: uploaded, 2: unchanged, 3: failed, 4: remaining. */ __( 'Uploaded %1$d, %2$d unchanged, %3$d failed, %4$d still queued.', 'sirius-press' ), $r['done'], $r['skipped'], $r['failed'], $r['left'] ); } elseif ( 'clear' === $action ) { SPE_Queue::clear_done(); $notes[] = __( 'Completed rows cleared.', 'sirius-press' ); } } $counts = SPE_Queue::counts(); $manual = SP_Settings::MODE_SERVER !== SP_Settings::mode(); echo '

' . esc_html__( 'Publishing', 'sirius-press' ) . '

'; foreach ( $notes as $n ) { printf( '

%s

', esc_html( $n ) ); } if ( ! SP_Settings::is_configured() ) { printf( '

%s %s

', esc_html__( 'No BCNR name is configured, so there is nowhere to publish to.', 'sirius-press' ), esc_url( admin_url( 'admin.php?page=sirius-press' ) ), esc_html__( 'Settings', 'sirius-press' ) ); echo '
'; return; } /* * Plain permalinks are fatal to a static export and the failure is * silent: every post's URL is `/?p=N`, whose path is `/`, so every * page in the site maps to index.html and each one overwrites the * last. The queue looks healthy the whole time. */ if ( '' === (string) get_option( 'permalink_structure' ) ) { printf( '

%s %s %s

', esc_html__( 'This site uses plain permalinks.', 'sirius-press' ), esc_html__( 'Every page would be exported to the same file and overwrite the one before it, so nothing useful can be published until that is changed.', 'sirius-press' ), esc_url( admin_url( 'options-permalink.php' ) ), esc_html__( 'Choose a permalink structure', 'sirius-press' ) ); } printf( '

%s %s%s

', esc_html__( 'Publishing to', 'sirius-press' ), esc_html( SP_Settings::name() ), $manual ? ' — ' . esc_html__( 'signing happens in your browser, on this page.', 'sirius-press' ) : ' — ' . esc_html__( 'this server signs uploads by itself.', 'sirius-press' ) ); printf( '

%1$d %2$s   %3$d %4$s   %5$d %6$s

', (int) $counts[ SPE_Queue::STATUS_PENDING ], esc_html__( 'queued', 'sirius-press' ), (int) $counts[ SPE_Queue::STATUS_DONE ], esc_html__( 'published', 'sirius-press' ), (int) $counts[ SPE_Queue::STATUS_FAILED ], esc_html__( 'failed', 'sirius-press' ) ); echo '
'; wp_nonce_field( 'sirius_export' ); echo ' '; if ( ! $manual ) { echo ' '; } echo ' '; echo ''; echo '
'; if ( $manual ) { self::render_manual_panel(); } self::render_queue_table(); echo ''; } private static function render_manual_panel() { ?>


' . esc_html__( 'Queue', 'sirius-press' ) . ''; if ( ! $rows ) { echo '

' . esc_html__( 'Nothing queued. Publish a post, or use “Export everything”.', 'sirius-press' ) . '

'; return; } echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; foreach ( $rows as $row ) { $colour = SPE_Queue::STATUS_FAILED === $row->status ? '#b32d2e' : ( SPE_Queue::STATUS_DONE === $row->status ? '#007017' : '#646970' ); printf( '', esc_html( $row->path ), esc_attr( $colour ), esc_html( $row->status ), (int) $row->attempts, esc_html( (string) $row->last_error ) ); } echo '
' . esc_html__( 'Path', 'sirius-press' ) . '' . esc_html__( 'Status', 'sirius-press' ) . '' . esc_html__( 'Tries', 'sirius-press' ) . '' . esc_html__( 'Last error', 'sirius-press' ) . '
%s%s%d%s
'; } }