diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php
index 4d72baa3b41b77f92b0b0eccd223ef218ddbc595..2a5bf861b938ea9a0c1342436c90e54b274f8df1 100644
--- a/module/VuFind/config/module.config.php
+++ b/module/VuFind/config/module.config.php
@@ -133,7 +133,8 @@ $staticRoutes = array(
     'Authority/Home', 'Authority/Record', 'Authority/Search',
     'Browse/Author', 'Browse/Dewey', 'Browse/Era', 'Browse/Genre', 'Browse/Home',
     'Browse/LCC', 'Browse/Region', 'Browse/Tag', 'Browse/Topic',
-    'Cart/Email', 'Cart/Export', 'Cart/Home', 'Cart/MyResearchBulk', 'Cart/Save',
+    'Cart/doExport', 'Cart/Email', 'Cart/Export', 'Cart/Home', 'Cart/MyResearchBulk',
+    'Cart/Save',
     'Cover/Show', 'Cover/Unavailable', 'Error/Unavailable', 'Help/Home',
     'Install/Done', 'Install/FixBasicConfig', 'Install/FixCache',
     'Install/FixDatabase', 'Install/FixDependencies', 'Install/FixILS',
diff --git a/module/VuFind/src/VuFind/Controller/AjaxController.php b/module/VuFind/src/VuFind/Controller/AjaxController.php
index 6a8f7f0d692e2658eef5aa9b47b20c4e1d6cabce..9c7b3e78d1b0ba90a4e04aa83fa00bec6c47100e 100644
--- a/module/VuFind/src/VuFind/Controller/AjaxController.php
+++ b/module/VuFind/src/VuFind/Controller/AjaxController.php
@@ -1193,21 +1193,21 @@ class AjaxController extends AbstractBase
      */
     protected function exportFavorites()
     {
-        /* TODO
-        $format = $this->params()->fromQuery('format');
+        $format = $this->params()->fromPost('format');
         $url = Export::getBulkUrl(
-            $this->view, $format, $this->params()->fromQuery('ids', array())
+            $this->getViewRenderer(), $format,
+            $this->params()->fromPost('ids', array())
+        );
+        $html = $this->getViewRenderer()->render(
+            'ajax/export-favorites.phtml',
+            array('url' => $url, 'format' => $format)
         );
-        $this->view->url = $url;
-        $this->view->format = $format;
-        $html = $this->getViewRenderer()->render('ajax/export-favorites.phtml');
         return $this->output(
             array(
                 'result' => Translator::translate('Done'),
                 'result_additional' => $html
             ), self::STATUS_OK
         );
-         */
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Controller/CartController.php b/module/VuFind/src/VuFind/Controller/CartController.php
index 9a931007d73406d64c624fc1cc2f5ff7070c0aba..a1eb988b8163059ae50c7310d6772a18cd2ceed9 100644
--- a/module/VuFind/src/VuFind/Controller/CartController.php
+++ b/module/VuFind/src/VuFind/Controller/CartController.php
@@ -61,7 +61,7 @@ class CartController extends AbstractBase
     {
         // We came in from the cart -- let's remember this we can redirect there
         // when we're done:
-        $this->session->url = '/Cart';
+        $this->session->url = $this->url()->fromRoute('cart-home');
 
         // Now forward to the requested action:
         if (strlen($this->params()->fromPost('email', '')) > 0) {
@@ -227,7 +227,6 @@ class CartController extends AbstractBase
      */
     public function exportAction()
     {
-        /* TODO
         // Get the desired ID list:
         $ids = is_null($this->params()->fromPost('selectAll'))
             ? $this->params()->fromPost('ids')
@@ -239,41 +238,43 @@ class CartController extends AbstractBase
         // Process form submission if necessary:
         if (!is_null($this->params()->fromPost('submit'))) {
             $format = $this->params()->fromPost('format');
-            $url = Export::getBulkUrl($this->view, $format, $ids);
+            $url = Export::getBulkUrl($this->getViewRenderer(), $format, $ids);
             if (Export::needsRedirect($format)) {
-                return $this->_redirect($url);
+                return $this->redirect()->toUrl($url);
             }
-            $this->view->url = $url;
             $msg = array(
                 'translate' => false, 'html' => true,
-                'msg' => $this->view->render('cart/export-success.phtml')
+                'msg' => $this->getViewRenderer()->render(
+                    'cart/export-success.phtml', array('url' => $url)
+                )
             );
             return $this->redirectToSource('info', $msg);
         }
 
         // Load the records:
-        $this->view->records = Record::loadBatch($ids);
+        $view = $this->createViewModel();
+        $view->records = Record::loadBatch($ids);
 
         // Assign the list of legal export options.  We'll filter them down based
         // on what the selected records actually support.
-        $this->view->exportOptions = Export::getBulkOptions();
-        foreach ($this->view->records as $driver) {
+        $view->exportOptions = Export::getBulkOptions();
+        foreach ($view->records as $driver) {
             // Filter out unsupported export formats:
             $newFormats = array();
-            foreach ($this->view->exportOptions as $current) {
+            foreach ($view->exportOptions as $current) {
                 if ($driver->supportsExport($current)) {
                     $newFormats[] = $current;
                 }
             }
-            $this->view->exportOptions = $newFormats;
+            $view->exportOptions = $newFormats;
         }
 
         // No legal export options?  Display a warning:
-        if (empty($this->view->exportOptions)) {
+        if (empty($view->exportOptions)) {
             $this->flashMessenger()->setNamespace('error')
                 ->addMessage('bulk_export_not_supported');
         }
-         */
+        return $view;
     }
 
     /**
@@ -283,11 +284,10 @@ class CartController extends AbstractBase
      */
     public function doexportAction()
     {
-        /* TODO
         // We use abbreviated parameters here to keep the URL short (there may
         // be a long list of IDs, and we don't want to run out of room):
-        $ids = $this->params()->fromPost('i', array());
-        $format = $this->params()->fromPost('f');
+        $ids = $this->params()->fromQuery('i', array());
+        $format = $this->params()->fromQuery('f');
 
         // Make sure we have IDs to export:
         if (!is_array($ids) || empty($ids)) {
@@ -295,22 +295,21 @@ class CartController extends AbstractBase
         }
 
         // Send appropriate HTTP headers for requested format:
-        Export::setHeaders($format, $this->getResponse());
+        $response = $this->getResponse();
+        $response->getHeaders()->addHeaders(Export::getHeaders($format));
 
-        // Turn off layouts and rendering -- we only want to display export data!
-        $this->_helper->viewRenderer->setNoRender();
-        $this->_helper->layout->disableLayout();
 
         // Actually export the records
         $records = Record::loadBatch($ids);
+        $recordHelper = $this->getViewRenderer()->plugin('record');
         $parts = array();
         foreach ($records as $record) {
-            $parts[] = $this->view->record($record)->getExport($format);
+            $parts[] = $recordHelper($record)->getExport($format);
         }
 
         // Process and display the exported records
-        $this->getResponse()->appendBody(Export::processGroup($format, $parts));
-         */
+        $response->setContent(Export::processGroup($format, $parts));
+        return $response;
     }
 
     /**
@@ -367,6 +366,7 @@ class CartController extends AbstractBase
     public function redirectToSource($flashNamespace = null, $flashMsg = null)
     {
         // Set flash message if requested:
+        // TODO: figure out why flash messages are not working after redirect!!
         if (!is_null($flashNamespace) && !empty($flashMsg)) {
             $this->flashMessenger()->setNamespace($flashNamespace)
                 ->addMessage($flashMsg);
diff --git a/module/VuFind/src/VuFind/Export.php b/module/VuFind/src/VuFind/Export.php
index fadfde3fb7c7b2810190fdcd8c4791624ebc986e..57ed33da2133bc154713b1b1473b49a4dcc7a9c1 100644
--- a/module/VuFind/src/VuFind/Export.php
+++ b/module/VuFind/src/VuFind/Export.php
@@ -71,9 +71,11 @@ class Export
     /**
      * Get the URL for bulk export.
      *
-     * @param Zend_View $view   View object (needed for URL generation)
-     * @param string    $format Export format being used
-     * @param array     $ids    Array of IDs to export (in source|id format)
+     * @param \Zend\View\Renderer\RendererInterface $view   View object (needed for
+     * URL generation)
+     * @param string                                $format Export format being used
+     * @param array                                 $ids    Array of IDs to export
+     * (in source|id format)
      *
      * @return string
      */
@@ -84,13 +86,10 @@ class Export
         foreach ($ids as $id) {
             $params[] = urlencode('i[]') . '=' . urlencode($id);
         }
-        $url = $view->fullUrl(
-            $view->url(
-                array('controller' => 'Cart', 'action' => 'doExport'), 'default',
-                true
-            )
-        );
-        $url .= '?' . implode('&', $params);
+        $serverUrlHelper = $view->plugin('serverurl');
+        $urlHelper = $view->plugin('url');
+        $url = $serverUrlHelper($urlHelper('cart-doexport'))
+            . '?' . implode('&', $params);
 
         return self::needsRedirect($format)
             ? self::getRedirectUrl($format, $url) : $url;