diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index fe6e06d..b3d9a3b 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -224,7 +224,7 @@ function book_form_update($form, FormStateInterface $form_state) {
 function book_node_load($nodes) {
   /** @var \Drupal\book\BookManagerInterface $book_manager */
   $book_manager = \Drupal::service('book.manager');
-  $links = $book_manager->loadBookLinks(array_keys($nodes), FALSE);
+  $links = $book_manager->loadBookLinks($nodes, FALSE);
   foreach ($links as $record) {
     $nodes[$record['nid']]->book = $record;
     $nodes[$record['nid']]->book['link_path'] = 'node/' . $record['nid'];
diff --git a/core/modules/book/book.services.yml b/core/modules/book/book.services.yml
index 9aeda19..1e0e702 100644
--- a/core/modules/book/book.services.yml
+++ b/core/modules/book/book.services.yml
@@ -6,7 +6,7 @@ services:
       - { name: breadcrumb_builder, priority: 701 }
   book.manager:
     class: Drupal\book\BookManager
-    arguments: ['@entity.manager', '@string_translation', '@config.factory', '@book.outline_storage']
+    arguments: ['@entity.manager', '@string_translation', '@config.factory', '@book.outline_storage', '@current_user']
   book.outline:
     class: Drupal\book\BookOutline
     arguments: ['@book.manager']
diff --git a/core/modules/book/src/BookManager.php b/core/modules/book/src/BookManager.php
index 3f5cfdc..847eabf 100644
--- a/core/modules/book/src/BookManager.php
+++ b/core/modules/book/src/BookManager.php
@@ -64,13 +64,26 @@ class BookManager implements BookManagerInterface {
   protected $bookTreeFlattened;
 
   /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $account;
+
+  /**
    * Constructs a BookManager object.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   * @param \Drupal\Core\StringTranslation\TranslationInterface $translation
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   * @param \Drupal\book\BookOutlineStorageInterface $book_outline_storage
+   * @param \Drupal\book\AcocuntInterface $account
    */
-  public function __construct(EntityManagerInterface $entity_manager, TranslationInterface $translation, ConfigFactoryInterface $config_factory, BookOutlineStorageInterface $book_outline_storage) {
+  public function __construct(EntityManagerInterface $entity_manager, TranslationInterface $translation, ConfigFactoryInterface $config_factory, BookOutlineStorageInterface $book_outline_storage, AccountInterface $account) {
     $this->entityManager = $entity_manager;
     $this->stringTranslation = $translation;
     $this->configFactory = $config_factory;
     $this->bookOutlineStorage = $book_outline_storage;
+    $this->account = $account;
   }
 
   /**
@@ -687,19 +700,22 @@ protected function flatBookTree(array $tree, array &$flat) {
    * {@inheritdoc}
    */
   public function loadBookLink($nid, $translate = TRUE) {
-    $links = $this->loadBookLinks(array($nid), $translate);
+    $links = [];
+    if ($node = $this->entityManager->getStorage('node')->load($nid)) {
+      $links = $this->loadBookLinks([$node->id() => $node], $translate);
+    }
     return isset($links[$nid]) ? $links[$nid] : FALSE;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function loadBookLinks($nids, $translate = TRUE) {
-    $result = $this->bookOutlineStorage->loadMultiple($nids);
+  public function loadBookLinks(array $nodes, $translate = TRUE) {
+    $result = $this->bookOutlineStorage->loadMultiple(array_keys($nodes), $translate);
     $links = array();
     foreach ($result as $link) {
       if ($translate) {
-        $this->bookLinkTranslate($link);
+        $this->bookLinkTranslate($link, $nodes[$link['nid']]);
       }
       $links[$link['nid']] = $link;
     }
@@ -879,15 +895,27 @@ protected function setParents(array &$link, array $parent) {
    * {@inheritdoc}
    */
   public function bookTreeCheckAccess(&$tree, $node_links = array()) {
+    $nodes = [];
     if ($node_links) {
       // @todo Extract that into its own method.
       $nids = array_keys($node_links);
 
       // @todo This should be actually filtering on the desired node status field
       //   language and just fall back to the default language.
-      $nids = \Drupal::entityQuery('node')
-        ->condition('nid', $nids)
-        ->condition('status', 1)
+      $query = \Drupal::entityQuery('node')->condition('nid', $nids);
+
+      // Allows admins to view all nodes, by both disabling node_access
+      // query rewrite as well as not checking for the node status. The
+      // 'view own unpublished nodes' permission is ignored to not require cache
+      // entries per user.
+      if ($this->account->hasPermission('bypass node access')) {
+        $query->accessCheck(FALSE);
+      }
+      else {
+        $query->condition('status', NODE_PUBLISHED);
+      }
+
+      $nids = $query
         ->execute();
 
       foreach ($nids as $nid) {
@@ -895,21 +923,29 @@ public function bookTreeCheckAccess(&$tree, $node_links = array()) {
           $node_links[$nid][$mlid]['access'] = TRUE;
         }
       }
+
+      $nodes = $this->entityManager->getStorage('node')->loadMultiple($nids);
     }
-    $this->doBookTreeCheckAccess($tree);
+
+    $this->doBookTreeCheckAccess($tree, $nodes);
   }
 
   /**
    * Sorts the menu tree and recursively checks access for each item.
+   *
+   * @param array $tree
+   *   The book tree you wish to operate on.
+   * @param \Drupal\node\NodeInterface[] $nodes
+   *   Loaded nodes of the tree.
    */
-  protected function doBookTreeCheckAccess(&$tree) {
+  protected function doBookTreeCheckAccess(&$tree, array $nodes) {
     $new_tree = array();
     foreach ($tree as $key => $v) {
       $item = &$tree[$key]['link'];
-      $this->bookLinkTranslate($item);
+      $this->bookLinkTranslate($item, isset($nodes[$item['nid']]) ? $nodes[$item['nid']] : NULL);
       if ($item['access']) {
         if ($tree[$key]['below']) {
-          $this->doBookTreeCheckAccess($tree[$key]['below']);
+          $this->doBookTreeCheckAccess($tree[$key]['below'], $nodes);
         }
         // The weights are made a uniform 5 digits by adding 50000 as an offset.
         // After calling $this->bookLinkTranslate(), $item['title'] has the
@@ -926,24 +962,21 @@ protected function doBookTreeCheckAccess(&$tree) {
   /**
    * {@inheritdoc}
    */
-  public function bookLinkTranslate(&$link) {
-    $node = NULL;
+  public function bookLinkTranslate(&$link, NodeInterface $node = NULL) {
+    // Try to load the node, if its not available yet.
+    $node = $node ?: $this->entityManager->getStorage('node')->load($link['nid']);
+    if (!$node) {
+      $link['access'] = FALSE;
+      return $link;
+    }
+
     // Access will already be set in the tree functions.
     if (!isset($link['access'])) {
-      $node = $this->entityManager->getStorage('node')->load($link['nid']);
-      $link['access'] = $node && $node->access('view');
-    }
-    // For performance, don't localize a link the user can't access.
-    if ($link['access']) {
-      // @todo - load the nodes en-mass rather than individually.
-      if (!$node) {
-        $node = $this->entityManager->getStorage('node')
-          ->load($link['nid']);
-      }
-      // The node label will be the value for the current user's language.
-      $link['title'] = $node->label();
-      $link['options'] = array();
+      $link['access'] = $node->access('view');
     }
+    // The node label will be the value for the current user's language.
+    $link['title'] = $node->label();
+    $link['options'] = array();
     return $link;
   }
 
diff --git a/core/modules/book/src/BookManagerInterface.php b/core/modules/book/src/BookManagerInterface.php
index 72ca61e..6f68683 100644
--- a/core/modules/book/src/BookManagerInterface.php
+++ b/core/modules/book/src/BookManagerInterface.php
@@ -70,8 +70,8 @@ public function loadBookLink($nid, $translate = TRUE);
   /**
    * Loads multiple book entries.
    *
-   * @param int[] $nids
-   *   An array of nids to load.
+   * @param \Drupal\node\NodeInterface[] $nodes
+   *   An array of nodes to load book entries by.
    *
    * @param bool $translate
    *   If TRUE, set access, title, and other elements.
@@ -79,7 +79,7 @@ public function loadBookLink($nid, $translate = TRUE);
    * @return array[]
    *   The book data of each node keyed by NID.
    */
-  public function loadBookLinks($nids, $translate = TRUE);
+  public function loadBookLinks(array $nodes, $translate = TRUE);
 
   /**
    * Returns an array of book pages in table of contents order.
diff --git a/core/modules/book/src/BookOutlineStorage.php b/core/modules/book/src/BookOutlineStorage.php
index 8e8271d..b99b57a 100644
--- a/core/modules/book/src/BookOutlineStorage.php
+++ b/core/modules/book/src/BookOutlineStorage.php
@@ -47,12 +47,16 @@ public function hasBooks() {
   /**
    * {@inheritdoc}
    */
-  public function loadMultiple($nids) {
+  public function loadMultiple($nids, $access = TRUE) {
     $query = $this->connection->select('book', 'b', array('fetch' => \PDO::FETCH_ASSOC));
     $query->fields('b');
     $query->condition('b.nid', $nids);
-    $query->addTag('node_access');
     $query->addMetaData('base_table', 'book');
+
+    if ($access) {
+      $query->addTag('node_access');
+    }
+
     return $query->execute();
   }
 
diff --git a/core/modules/book/src/BookOutlineStorageInterface.php b/core/modules/book/src/BookOutlineStorageInterface.php
index e08fab6..f89a3cb 100644
--- a/core/modules/book/src/BookOutlineStorageInterface.php
+++ b/core/modules/book/src/BookOutlineStorageInterface.php
@@ -33,11 +33,13 @@ public function hasBooks();
    *
    * @param array $nids
    *   An array of node IDs.
+   * @param bool $access
+   *   (optional) TRUE if access should be taken into account
    *
    * @return array
    *   Array of loaded book items.
    */
-  public function loadMultiple($nids);
+  public function loadMultiple($nids, $access = TRUE);
 
   /**
    * Gets child relative depth.
