diff --git a/esoui/internalingame/market/keyboard/market_keyboard.lua b/esoui/internalingame/market/keyboard/market_keyboard.lua
index 90f35c6..d5c5725 100755
--- a/esoui/internalingame/market/keyboard/market_keyboard.lua
+++ b/esoui/internalingame/market/keyboard/market_keyboard.lua
@@ -20,6 +20,16 @@ function Market:Initialize(control)
     self.messageLoadingIcon = self.control:GetNamedChild("MessageLoadingIcon")
     self.rotationControl = self.control:GetNamedChild("RotationArea")
     self.noMatchesMessage = self.contentsControl:GetNamedChild("NoMatchMessage")
+    self.searchBox = self.contentsControl:GetNamedChild("Search"):GetNamedChild("Box");
+
+    local subscriptionControl = self.contentsControl:GetNamedChild("SubscriptionPage")
+    self.subscriptionPage = subscriptionControl
+    self.subscriptionOverviewLabel = subscriptionControl:GetNamedChild("Overview")
+    self.subscriptionStatusLabel = subscriptionControl:GetNamedChild("MembershipInfoStatus")
+    self.subscriptionBenefitsLabel = subscriptionControl:GetNamedChild("BenefitsText")
+    self.subscriptionBenefitsImage = subscriptionControl:GetNamedChild("BenefitsImage")
+    self.subscriptionSubscribeButton = subscriptionControl:GetNamedChild("SubscribeButton")
+
     self.nextPreviewChangeTime = 0
     self.canBeginPreview = true
 
@@ -170,6 +180,19 @@ function Market:InitializeCategories()
 
         if selected and not reselectingDuringRebuild then
             self:OnCategorySelected(data)
+
+            local categoryIndex, subCategoryIndex
+            -- faked category types don't have real category indices so keep them as nil
+            if data.type == ZO_MARKET_CATEGORY_TYPE_NONE then
+                if data.parentData then
+                    categoryIndex = data.parentData.categoryIndex
+                    subCategoryIndex = data.categoryIndex
+                else
+                    categoryIndex = data.categoryIndex
+                end
+            end
+
+            OnMarketCategorySelected(categoryIndex, subCategoryIndex)
         end
     end
 
@@ -196,6 +219,13 @@ function Market:InitializeMarketList()
     self.marketProductList = self.contentsControl:GetNamedChild("EntryList")
     self.marketScrollChild = self.marketProductList:GetNamedChild("ScrollChild")
 
+    -- override the default functionality when the extants change for the product list so we can scroll to a specific item
+    -- if one exists because we openned the market to see a specific item
+    self.marketProductList.scroll:SetHandler("OnScrollExtentsChanged", function(control)
+                                                                                   ZO_Scroll_OnExtentsChanged(control:GetParent()) 
+                                                                                   self:ScrollAndPreviewQueuedMarketProduct()
+                                                                                   end)
+
     -- MarketProductIcon Pool
 
     local function CreateMarketProductIcon(objectPool)
@@ -243,9 +273,17 @@ function Market:BuildCategories()
         --Special featured items blade
         local numFeaturedMarketProducts = GetNumFeaturedMarketProducts()
         if numFeaturedMarketProducts > 0 then
-            self:AddTopLevelCategory(nil, GetString(SI_MARKET_FEATURED_CATEGORY), 0)
+            local normalIcon = "esoui/art/treeicons/achievements_indexicon_summary_up.dds"
+            local pressedIcon = "esoui/art/treeicons/achievements_indexicon_summary_down.dds"
+            local mouseoverIcon = "esoui/art/treeicons/achievements_indexicon_summary_over.dds"
+            self:AddTopLevelCategory(ZO_MARKET_FEATURED_CATEGORY_INDEX, GetString(SI_MARKET_FEATURED_CATEGORY), 0, normalIcon, pressedIcon, mouseoverIcon, ZO_MARKET_CATEGORY_TYPE_FEATURED)
         end
 
+        local normalIcon = "esoui/art/treeicons/store_indexIcon_ESOPlus_up.dds"
+        local pressedIcon = "esoui/art/treeicons/store_indexIcon_ESOPlus_down.dds"
+        local mouseoverIcon = "esoui/art/treeicons/store_indexIcon_ESOPlus_over.dds"
+        self:AddTopLevelCategory(ZO_MARKET_ESO_PLUS_CATEGORY_INDEX, GetString(SI_MARKET_ESO_PLUS_CATEGORY), 0, normalIcon, pressedIcon, mouseoverIcon, ZO_MARKET_CATEGORY_TYPE_ESO_PLUS)
+
         for i = 1, GetNumMarketProductCategories() do
             local name, numSubCategories, numMarketProducts, normalIcon, pressedIcon, mouseoverIcon = GetMarketProductCategoryInfo(i)
             self:AddTopLevelCategory(i, name, numSubCategories, normalIcon, pressedIcon, mouseoverIcon)
@@ -268,38 +306,40 @@ function Market:BuildCategories()
         else
             categoryIndex = currentCategory.categoryIndex
         end
-        nodeToSelect = self:LookupTreeNodeForData(categoryIndex, subcatgoryIndex)
+        nodeToSelect = self:GetCategoryData(categoryIndex, subcatgoryIndex)
     end
 
     self.categoryTree:Commit(nodeToSelect)
+
+    self.refreshCategories = false
 end
 
 function Market:RefreshVisibleCategoryFilter()
     local data = self.categoryTree:GetSelectedData()
-    if(data ~= nil) then
+    if data ~= nil then
         self:OnCategorySelected(data)
     end
 end
 
 do
     local function AddNodeLookup(lookup, node, parent, categoryIndex)
-        if(categoryIndex ~= nil) then
+        if categoryIndex ~= nil then
             local parentCategory = categoryIndex
             local subCategory
 
-            if(parent) then
+            if parent then
                 parentCategory = parent.data.categoryIndex
                 subCategory = categoryIndex
             end
 
             local categoryTable = lookup[parentCategory]
             
-            if(categoryTable == nil) then
+            if categoryTable == nil then
                 categoryTable = { subCategories = {} }
                 lookup[parentCategory] = categoryTable
             end
 
-            if(subCategory) then
+            if subCategory then
                 categoryTable.subCategories[subCategory] = node
             else
                 categoryTable.node = node
@@ -307,14 +347,14 @@ do
         end
     end
 
-    function Market:LookupTreeNodeForData(categoryIndex, subCategoryIndex)
-        if(categoryIndex ~= nil) then
+    function Market:GetCategoryData(categoryIndex, subCategoryIndex)
+        if categoryIndex ~= nil then
             local categoryTable = self.nodeLookupData[categoryIndex]
-            if(categoryTable ~= nil) then
-                if(subCategoryIndex ~= nil) then
+            if categoryTable ~= nil then
+                if subCategoryIndex ~= nil then
                     return categoryTable.subCategories[subCategoryIndex]
                 else
-                    if(categoryTable.node:IsLeaf()) then
+                    if categoryTable.node:IsLeaf() then
                         return categoryTable.node
                     else
                         return categoryTable.node:GetChildren()[1]
@@ -324,13 +364,83 @@ do
         end
     end
 
-    local function AddCategory(lookup, tree, nodeTemplate, parent, categoryIndex, name, normalIcon, pressedIcon, mouseoverIcon, isFeaturedCategory, isFakedSubcategory)
+    function Market:GetMarketProductInfo(productId)
+        for i = 1, #self.marketProducts do
+            if self.marketProducts[i].product:GetId() == productId then
+                return self.marketProducts[i]
+            end
+        end
+
+        for i = 1, #self.featuredProducts do
+            if self.featuredProducts[i].product:GetId() == productId then
+                return self.featuredProducts[i]
+            end
+        end
+
+        for i = 1, #self.limitedTimedOfferProducts do
+            if self.limitedTimedOfferProducts[i].product:GetId() == productId then
+                return self.limitedTimedOfferProducts[i]
+            end
+        end
+    end
+
+    function Market:RequestShowMarketProduct(id)
+        if self.marketState ~= MARKET_STATE_OPEN then
+            self.queuedMarketProductId = id
+            return
+        end
+
+        local targetNode = self:GetCategoryDataForMarketProduct(id)
+        if targetNode then
+            if self.categoryTree:GetSelectedNode() == targetNode then
+                self:ScrollAndPreviewMarketProduct(id)
+            else
+                self.categoryTree:SelectNode(targetNode)
+                self.queuedMarketProductId = id -- order of operations is important here
+            end
+        end
+    end
+
+    local INSTANTLY_SCROLL_TO_CENTER = true
+    function Market:ScrollAndPreviewMarketProduct(marketProductId)
+        local marketProductInfo = self:GetMarketProductInfo(marketProductId)
+        if marketProductInfo then
+            ZO_Scroll_ScrollControlIntoCentralView(self.marketProductList, marketProductInfo.control, INSTANTLY_SCROLL_TO_CENTER)
+            marketProductInfo.product:PlayHighlightAnimationToEnd()
+            self.queuedMarketProductPreview = marketProductInfo.product
+        end
+    end
+
+    function Market:ScrollAndPreviewQueuedMarketProduct()
+        self:ScrollAndPreviewMarketProduct(self.queuedMarketProductId)
+        self.queuedMarketProductId = nil
+    end
+
+    function Market:RequestShowMarketWithSearchString(searchString)
+        if self.marketState ~= MARKET_STATE_OPEN then
+            self.queuedSearchString = searchString
+            return
+        end
+
+        self:DisplayMarketProductsBySearchString(searchString)
+    end
+
+    function Market:DisplayMarketProductsBySearchString(searchString)
+        self.searchBox:SetText(searchString)
+    end
+
+    function Market:DisplayQueuedMarketProductsBySearchString()
+        self:DisplayMarketProductsBySearchString(self.queuedSearchString)
+        self.queuedSearchString = nil
+    end
+
+    local function AddCategory(lookup, tree, nodeTemplate, parent, categoryIndex, name, normalIcon, pressedIcon, mouseoverIcon, categoryType)
+        categoryType = categoryType or ZO_MARKET_CATEGORY_TYPE_NONE
         local entryData = 
         {
-            isFakedSubcategory = isFakedSubcategory,
             categoryIndex = categoryIndex,
             name = zo_strformat(SI_MARKET_PRODUCT_NAME_FORMATTER, name),
-            featured = isFeaturedCategory,
+            type = categoryType,
             parentData = parent and parent.data or nil,
             normalIcon = normalIcon,
             pressedIcon = pressedIcon,
@@ -345,35 +455,7 @@ do
         return node
     end
 
-    local featuredIcons =
-    {
-        "esoui/art/treeicons/achievements_indexicon_summary_up.dds",
-        "esoui/art/treeicons/achievements_indexicon_summary_down.dds",
-        "esoui/art/treeicons/achievements_indexicon_summary_over.dds",
-    }
-    
-    local SPOTLIT = 1
-    local IS_NEW = 2
-    local ON_SALE = 3
-    
-    local FEATURED_SUBCATEGORY_FILTER =
-    {
-        -- spotlit is featured but nothing else "special" about it
-        [SPOTLIT] = function(id)
-            local _, _, cost, discountedCost, _, _, isNew = GetMarketProductInfo(id)
-            return not (cost > discountedCost or isNew)
-        end,
-        [IS_NEW] = function(id) return select(7, GetMarketProductInfo(id)) end,
-        [ON_SALE] = function(id) 
-            local _, _, cost, discountedCost = GetMarketProductInfo(id)
-            return cost > discountedCost
-        end
-    }
-    
-    local FEATURED_CATEGORY_INDEX = 0
-
-    function Market:AddTopLevelCategory(categoryIndex, name, numSubCategories, normalIcon, pressedIcon, mouseoverIcon)
-        local isFeaturedCategory = categoryIndex == nil
+    function Market:AddTopLevelCategory(categoryIndex, name, numSubCategories, normalIcon, pressedIcon, mouseoverIcon, categoryType)
         local tree = self.categoryTree
         local lookup = self.nodeLookupData
 
@@ -381,13 +463,9 @@ do
         local searchResultsWithChildren = self.searchString ~= "" and (NonContiguousCount(self.searchResults[categoryIndex]) > 1 or self.searchResults[categoryIndex]["root"] == nil)
         local hasChildren = numSubCategories > 0 --Only for non-search results
 
-        local nodeTemplate = (hasChildren or isFeaturedCategory) and "ZO_IconHeader" or "ZO_MarketChildlessCategory"
-
-        if isFeaturedCategory then
-            normalIcon, pressedIcon, mouseoverIcon = unpack(featuredIcons)
-        end
+        local nodeTemplate = hasChildren and "ZO_IconHeader" or "ZO_MarketChildlessCategory"
 
-        local parent = AddCategory(lookup, tree, nodeTemplate, nil, isFeaturedCategory and FEATURED_CATEGORY_INDEX or categoryIndex, name, normalIcon, pressedIcon, mouseoverIcon, isFeaturedCategory)
+        local parent = AddCategory(lookup, tree, nodeTemplate, nil, categoryIndex, name, normalIcon, pressedIcon, mouseoverIcon, categoryType)
 
         if searchResultsWithChildren then
             for subcategoryIndex, data in pairs(self.searchResults[categoryIndex]) do
@@ -401,60 +479,23 @@ do
                 local subCategoryName, numSubCategoryMarketProducts = GetMarketProductSubCategoryInfo(categoryIndex, i)
                 AddCategory(lookup, tree, "ZO_MarketSubCategory", parent, i, subCategoryName, normalIcon, pressedIcon, mouseoverIcon)
             end
-        elseif isFeaturedCategory then
-            local hasSpotlitCategory = false
-            local hasNewSubCategory = false
-            local hasOnSaleSubCategory = false
-            local numFeaturedMarketProducts = GetNumFeaturedMarketProducts()
-
-            -- search the featured products to find the presence of products in various subcategories including New and On Sale. 
-            -- This way only subcategories that have contents will be displayed as selectable.
-            for i = 1, numFeaturedMarketProducts do
-                local featuredProductId = GetFeaturedMarketProductId(i)
-                local name, description, cost, discountedCost, discountPercent, icon, isNew, isFeatured = GetMarketProductInfo(featuredProductId)
-                
-                hasNewSubCategory = hasNewSubCategory or isNew
-                hasOnSaleSubCategory = hasOnSaleSubCategory or (cost > discountedCost)
-                hasSpotlitCategory = hasSpotlitCategory or not (isNew or (cost > discountedCost))
-                
-                if hasNewSubCategory and hasOnSaleSubCategory then
-                    break
-                end
-            end
-            
-            if hasSpotlitCategory then
-                AddCategory(lookup, tree, "ZO_MarketSubCategory", parent, SPOTLIT, GetString(SI_MARKET_FEATURED_SUBCATEGORY), normalIcon, pressedIcon, mouseoverIcon, isFeaturedCategory)
-            end
-            
-            if hasNewSubCategory then
-                AddCategory(lookup, tree, "ZO_MarketSubCategory", parent, IS_NEW, GetString(SI_MARKET_NEW_LABEL), normalIcon, pressedIcon, mouseoverIcon, isFeaturedCategory)
-            end
-            
-            if hasOnSaleSubCategory then
-                AddCategory(lookup, tree, "ZO_MarketSubCategory", parent, ON_SALE, GetString(SI_MARKET_DISCOUNT_LABEL), normalIcon, pressedIcon, mouseoverIcon, isFeaturedCategory)
-            end
         end
 
         return parent
     end
     
-    local function GetFeaturedSubCategoryProductIds(filterFunc, index, ...)
+    local function GetFeaturedSubCategoryProductIds(index, ...)
         if index >= 1 then
             local id = GetFeaturedMarketProductId(index)
             index = index - 1
-            if filterFunc(id) then
-                return GetFeaturedSubCategoryProductIds(filterFunc, index, id, ...)
-            else
-                return GetFeaturedSubCategoryProductIds(filterFunc, index, ...)
-            end
+            return GetFeaturedSubCategoryProductIds(index, id, ...)
         end
         return ...
     end
     
     function Market:BuildFeaturedMarketProductList(data)
         local numFeaturedMarketProducts = GetNumFeaturedMarketProducts()
-        local filterFunc = FEATURED_SUBCATEGORY_FILTER[data.categoryIndex]
-        self:LayoutMarketProducts(GetFeaturedSubCategoryProductIds(filterFunc, numFeaturedMarketProducts))
+        self:LayoutMarketProducts(GetFeaturedSubCategoryProductIds(numFeaturedMarketProducts))
     end
 end
 
@@ -537,13 +578,40 @@ do
     end
 end
 
-local NO_LABELED_GROUP_HEADER = nil
-function Market:LayoutMarketProducts(...)
+function Market:ClearMarketProducts()
     self.marketProductPool:ReleaseAllObjects()
     self.marketProductBundlePool:ReleaseAllObjects()
     self:ClearLabeledGroups()
     ZO_Scroll_ResetToTop(self.marketProductList)
     self.previousRowControl = nil
+end
+
+function Market:DisplayEsoPlusOffer()
+    self:ClearMarketProducts()
+
+    self.subscriptionPage:SetHidden(false)
+
+    local overview, benefits, image = GetMarketSubscriptionKeyboardInfo()
+
+    self.subscriptionOverviewLabel:SetText(overview)
+    self.subscriptionBenefitsLabel:SetText(benefits)
+    self.subscriptionBenefitsImage:SetTexture(image)
+
+    local isSubscribed = IsESOPlusSubscriber()
+    local statusText = isSubscribed and SI_MARKET_SUBSCRIPTION_PAGE_SUBSCRIPTION_STATUS_ACTIVE or SI_MARKET_SUBSCRIPTION_PAGE_SUBSCRIPTION_STATUS_NOT_ACTIVE
+
+    self.subscriptionSubscribeButton:SetEnabled(not isSubscribed)
+
+    self.subscriptionStatusLabel:SetText(GetString(statusText))
+end
+
+local NO_LABELED_GROUP_HEADER = nil
+function Market:LayoutMarketProducts(...)
+    self:ClearMarketProducts()
+
+    self.subscriptionPage:SetHidden(true)
+
+    local categoryType = self.currentCategoryData.type
 
     local filterType = self.categoryFilter.filterType
     local hasShownProduct = false
@@ -559,18 +627,40 @@ function Market:LayoutMarketProducts(...)
             marketProduct:Show(id)
 
             local name, description, cost, discountedCost, discountPercent, icon, isNew, isFeatured = marketProduct:GetMarketProductInfo()
+            local timeLeft = marketProduct:GetTimeLeftInSeconds()
+            -- durations longer than 1 month aren't represented to the user, so it's effectively not limited time
+            local isLimitedTime = timeLeft > 0 and timeLeft <= ZO_ONE_MONTH_IN_SECONDS
+            local doesContainDLC = DoesMarketProductContainDLC(id)
 
             -- only show the market product in the featured section or the all section
-            if not self.currentCategoryData.featured and isFeatured then
+            if doesContainDLC and categoryType == ZO_MARKET_CATEGORY_TYPE_FEATURED then
+                self:AddProductToLabeledGroupTable(self.dlcProducts, name, marketProduct)
+            else
+                if isLimitedTime then
+                    self:AddProductToLabeledGroupTable(self.limitedTimedOfferProducts, name, marketProduct)
+                elseif isFeatured then
                     self:AddProductToLabeledGroupTable(self.featuredProducts, name, marketProduct)
                 else
                     self:AddProductToLabeledGroupTable(self.marketProducts, name, marketProduct)
                 end
             end
         end
+    end
 
-    if not self.currentCategoryData.featured and #self.featuredProducts > 0 then
+    if #self.limitedTimedOfferProducts > 0 then
+        self:AddLabeledGroupTable(GetString(SI_MARKET_LIMITED_TIME_OFFER_CATEGORY), self.limitedTimedOfferProducts)
+    end
+
+    if #self.dlcProducts > 0 then
+        self:AddLabeledGroupTable(GetString(SI_MARKET_DLC_CATEGORY), self.dlcProducts)
+    end
+
+    if #self.featuredProducts > 0 then
+        if categoryType == ZO_MARKET_CATEGORY_TYPE_NONE then
             self:AddLabeledGroupTable(GetString(SI_MARKET_FEATURED_CATEGORY), self.featuredProducts)
+        else -- featured
+            self:AddLabeledGroupTable(GetString(SI_MARKET_ALL_LABEL), self.featuredProducts)
+        end
     end
 
     local categoryHeader = (#self.labeledGroups > 0) and GetString(SI_MARKET_ALL_LABEL) or NO_LABELED_GROUP_HEADER
@@ -579,6 +669,7 @@ function Market:LayoutMarketProducts(...)
 end
 
 function Market:ShowMarket(showMarket)
+    ZO_Market_Shared.ShowMarket(self, showMarket)
     self.contentsControl:SetHidden(not showMarket)
     self.messageLabel:SetHidden(showMarket)
     self.rotationControl:SetHidden(not showMarket)
@@ -661,6 +752,15 @@ end
 function Market:OnShown()
     self:AddKeybinds()
     ZO_Market_Shared.OnShown(self)
+
+    if self.refreshCategories then
+        self:BuildCategories()
+    end
+
+    if self.queuedMarketProductPreview and IsCharacterPreviewingAvailable() then
+        self.queuedMarketProductPreview:Preview()
+        self.queuedMarketProductPreview = nil
+    end
 end
 
 function Market:OnHidden()
@@ -678,6 +778,16 @@ function Market:RefreshProducts()
         local product = self.featuredProducts[i].product
         product:Refresh()
     end
+
+    for i = 1, #self.limitedTimedOfferProducts do
+        local product = self.limitedTimedOfferProducts[i].product
+        product:Refresh()
+    end
+
+    for i = 1, #self.dlcProducts do
+        local product = self.dlcProducts[i].product
+        product:Refresh()
+    end
 end
 
 function Market:RestoreActionLayerForTutorial()
@@ -689,6 +799,10 @@ function Market:RemoveActionLayerForTutorial()
     RemoveActionLayerByName(GetString(SI_KEYBINDINGS_LAYER_USER_INTERFACE_SHORTCUTS))
 end
 
+function Market:ResetSearch()
+    self.searchBox:SetText("")
+end
+
 --
 --[[ XML Handlers ]]--
 --
@@ -724,7 +838,11 @@ function ZO_MarketCurrency_OnMouseExit(control)
     ClearTooltip(InformationTooltip)
 end
 
-
 function ZO_MarketCurrencyBuyCrowns_OnClicked(control)
-    ZO_Dialogs_ShowDialog("MARKET_CONFIRM_OPEN_URL", ZO_BUY_CROWNS_URL, ZO_BUY_CROWNS_FRONT_FACING_ADDRESS)
+    OnMarketPurchaseMoreCrowns()
+    ZO_Dialogs_ShowDialog("CONFIRM_OPEN_URL_BY_TYPE", ZO_BUY_CROWNS_URL_TYPE, ZO_BUY_CROWNS_FRONT_FACING_ADDRESS)
+end
+
+function ZO_MarketCurrencyBuySubscription_OnClicked(control)
+    ZO_Dialogs_ShowDialog("CONFIRM_OPEN_URL_BY_TYPE", ZO_BUY_SUBSCRIPTION_URL_TYPE, ZO_BUY_SUBSCRIPTION_FRONT_FACING_ADDRESS)
 end
\ No newline at end of file