diff --git a/app/Entity.php b/app/Entity.php
index 5ea1d3876..1342c2997 100644
--- a/app/Entity.php
+++ b/app/Entity.php
@@ -157,48 +157,54 @@ class Entity extends Ownable
      * @param string[] array $wheres
      * @return mixed
      */
-    public static function fullTextSearchQuery($fieldsToSearch, $terms, $wheres = [])
+    public function fullTextSearchQuery($fieldsToSearch, $terms, $wheres = [])
     {
         $exactTerms = [];
-        foreach ($terms as $key => $term) {
-            $term = htmlentities($term, ENT_QUOTES);
-            $term = preg_replace('/[+\-><\(\)~*\"@]+/', ' ', $term);
-            if (preg_match('/\s/', $term)) {
-                $exactTerms[] = '%' . $term . '%';
-                $term = '"' . $term . '"';
-            } else {
-                $term = '' . $term . '*';
-            }
-            if ($term !== '*') $terms[$key] = $term;
-        }
-        $termString = implode(' ', $terms);
-        $fields = implode(',', $fieldsToSearch);
-        $search = static::selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]);
-        $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]);
-
-        // Ensure at least one exact term matches if in search
-        if (count($exactTerms) > 0) {
-            $search = $search->where(function ($query) use ($exactTerms, $fieldsToSearch) {
-                foreach ($exactTerms as $exactTerm) {
-                    foreach ($fieldsToSearch as $field) {
-                        $query->orWhere($field, 'like', $exactTerm);
-                    }
+        if (count($terms) === 0) {
+            $search = $this;
+            $orderBy = 'updated_at';
+        } else {
+            foreach ($terms as $key => $term) {
+                $term = htmlentities($term, ENT_QUOTES);
+                $term = preg_replace('/[+\-><\(\)~*\"@]+/', ' ', $term);
+                if (preg_match('/\s/', $term)) {
+                    $exactTerms[] = '%' . $term . '%';
+                    $term = '"' . $term . '"';
+                } else {
+                    $term = '' . $term . '*';
                 }
-            });
-        }
+                if ($term !== '*') $terms[$key] = $term;
+            }
+            $termString = implode(' ', $terms);
+            $fields = implode(',', $fieldsToSearch);
+            $search = static::selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]);
+            $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]);
+
+            // Ensure at least one exact term matches if in search
+            if (count($exactTerms) > 0) {
+                $search = $search->where(function ($query) use ($exactTerms, $fieldsToSearch) {
+                    foreach ($exactTerms as $exactTerm) {
+                        foreach ($fieldsToSearch as $field) {
+                            $query->orWhere($field, 'like', $exactTerm);
+                        }
+                    }
+                });
+            }
+            $orderBy = 'title_relevance';
+        };
 
         // Add additional where terms
         foreach ($wheres as $whereTerm) {
             $search->where($whereTerm[0], $whereTerm[1], $whereTerm[2]);
         }
         // Load in relations
-        if (static::isA('page')) {
+        if ($this->isA('page')) {
             $search = $search->with('book', 'chapter', 'createdBy', 'updatedBy');
-        } else if (static::isA('chapter')) {
+        } else if ($this->isA('chapter')) {
             $search = $search->with('book');
         }
 
-        return $search->orderBy('title_relevance', 'desc');
+        return $search->orderBy($orderBy, 'desc');
     }
     
 }
diff --git a/app/Repos/BookRepo.php b/app/Repos/BookRepo.php
index e62b101c5..b0530b4f5 100644
--- a/app/Repos/BookRepo.php
+++ b/app/Repos/BookRepo.php
@@ -286,8 +286,9 @@ class BookRepo extends EntityRepo
     public function getBySearch($term, $count = 20, $paginationAppends = [])
     {
         $terms = $this->prepareSearchTerms($term);
-        $books = $this->permissionService->enforceBookRestrictions($this->book->fullTextSearchQuery(['name', 'description'], $terms))
-            ->paginate($count)->appends($paginationAppends);
+        $bookQuery = $this->permissionService->enforceBookRestrictions($this->book->fullTextSearchQuery(['name', 'description'], $terms));
+        $bookQuery = $this->addAdvancedSearchQueries($bookQuery, $term);
+        $books = $bookQuery->paginate($count)->appends($paginationAppends);
         $words = join('|', explode(' ', preg_quote(trim($term), '/')));
         foreach ($books as $book) {
             //highlight
diff --git a/app/Repos/ChapterRepo.php b/app/Repos/ChapterRepo.php
index 0980e93a7..048e0a63b 100644
--- a/app/Repos/ChapterRepo.php
+++ b/app/Repos/ChapterRepo.php
@@ -168,8 +168,9 @@ class ChapterRepo extends EntityRepo
     public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = [])
     {
         $terms = $this->prepareSearchTerms($term);
-        $chapters = $this->permissionService->enforceChapterRestrictions($this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms))
-            ->paginate($count)->appends($paginationAppends);
+        $chapterQuery = $this->permissionService->enforceChapterRestrictions($this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms));
+        $chapterQuery = $this->addAdvancedSearchQueries($chapterQuery, $term);
+        $chapters = $chapterQuery->paginate($count)->appends($paginationAppends);
         $words = join('|', explode(' ', preg_quote(trim($term), '/')));
         foreach ($chapters as $chapter) {
             //highlight
diff --git a/app/Repos/EntityRepo.php b/app/Repos/EntityRepo.php
index 6b4076e6e..012a64967 100644
--- a/app/Repos/EntityRepo.php
+++ b/app/Repos/EntityRepo.php
@@ -6,6 +6,7 @@ use BookStack\Entity;
 use BookStack\Page;
 use BookStack\Services\PermissionService;
 use BookStack\User;
+use Illuminate\Support\Facades\Log;
 
 class EntityRepo
 {
@@ -30,6 +31,12 @@ class EntityRepo
      */
     protected $permissionService;
 
+    /**
+     * Acceptable operators to be used in a query
+     * @var array
+     */
+    protected $queryOperators = ['<=', '>=', '=', '<', '>', 'like', '!='];
+
     /**
      * EntityService constructor.
      */
@@ -163,6 +170,7 @@ class EntityRepo
      */
     protected function prepareSearchTerms($termString)
     {
+        $termString = $this->cleanSearchTermString($termString);
         preg_match_all('/"(.*?)"/', $termString, $matches);
         if (count($matches[1]) > 0) {
             $terms = $matches[1];
@@ -174,5 +182,93 @@ class EntityRepo
         return $terms;
     }
 
+    /**
+     * Removes any special search notation that should not
+     * be used in a full-text search.
+     * @param $termString
+     * @return mixed
+     */
+    protected function cleanSearchTermString($termString)
+    {
+        // Strip tag searches
+        $termString = preg_replace('/\[.*?\]/', '', $termString);
+        // Reduced multiple spacing into single spacing
+        $termString = preg_replace("/\s{2,}/", " ", $termString);
+        return $termString;
+    }
+
+    /**
+     * Get the available query operators as a regex escaped list.
+     * @return mixed
+     */
+    protected function getRegexEscapedOperators()
+    {
+        $escapedOperators = [];
+        foreach ($this->queryOperators as $operator) {
+            $escapedOperators[] = preg_quote($operator);
+        }
+        return join('|', $escapedOperators);
+    }
+
+    /**
+     * Parses advanced search notations and adds them to the db query.
+     * @param $query
+     * @param $termString
+     * @return mixed
+     */
+    protected function addAdvancedSearchQueries($query, $termString)
+    {
+        $escapedOperators = $this->getRegexEscapedOperators();
+        // Look for tag searches
+        preg_match_all("/\[(.*?)((${escapedOperators})(.*?))?\]/", $termString, $tags);
+        if (count($tags[0]) > 0) {
+            $this->applyTagSearches($query, $tags);
+        }
+
+        return $query;
+    }
+
+    /**
+     * Apply extracted tag search terms onto a entity query.
+     * @param $query
+     * @param $tags
+     * @return mixed
+     */
+    protected function applyTagSearches($query, $tags) {
+        $query->where(function($query) use ($tags) {
+            foreach ($tags[1] as $index => $tagName) {
+                $query->whereHas('tags', function($query) use ($tags, $index, $tagName) {
+                    $tagOperator = $tags[3][$index];
+                    $tagValue = $tags[4][$index];
+                    if (!empty($tagOperator) && !empty($tagValue) && in_array($tagOperator, $this->queryOperators)) {
+                        if (is_numeric($tagValue) && $tagOperator !== 'like') {
+                            // We have to do a raw sql query for this since otherwise PDO will quote the value and MySQL will
+                            // search the value as a string which prevents being able to do number-based operations
+                            // on the tag values. We ensure it has a numeric value and then cast it just to be sure.
+                            $tagValue = (float) trim($query->getConnection()->getPdo()->quote($tagValue), "'");
+                            $query->where('name', '=', $tagName)->whereRaw("value ${tagOperator} ${tagValue}");
+                        } else {
+                            $query->where('name', '=', $tagName)->where('value', $tagOperator, $tagValue);
+                        }
+                    } else {
+                        $query->where('name', '=', $tagName);
+                    }
+                });
+            }
+        });
+        return $query;
+    }
+
+}
+
+
+
+
+
+
+
+
+
+
+
 
-}
\ No newline at end of file
diff --git a/app/Repos/PageRepo.php b/app/Repos/PageRepo.php
index a28717b76..992e97cda 100644
--- a/app/Repos/PageRepo.php
+++ b/app/Repos/PageRepo.php
@@ -245,8 +245,9 @@ class PageRepo extends EntityRepo
     public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = [])
     {
         $terms = $this->prepareSearchTerms($term);
-        $pages = $this->permissionService->enforcePageRestrictions($this->page->fullTextSearchQuery(['name', 'text'], $terms, $whereTerms))
-            ->paginate($count)->appends($paginationAppends);
+        $pageQuery = $this->permissionService->enforcePageRestrictions($this->page->fullTextSearchQuery(['name', 'text'], $terms, $whereTerms));
+        $pageQuery = $this->addAdvancedSearchQueries($pageQuery, $term);
+        $pages = $pageQuery->paginate($count)->appends($paginationAppends);
 
         // Add highlights to page text.
         $words = join('|', explode(' ', preg_quote(trim($term), '/')));
diff --git a/resources/views/pages/page-display.blade.php b/resources/views/pages/page-display.blade.php
index df555da07..d0bdcf880 100644
--- a/resources/views/pages/page-display.blade.php
+++ b/resources/views/pages/page-display.blade.php
@@ -8,8 +8,8 @@
             <table>
                 @foreach($page->tags as $tag)
                     <tr class="tag">
-                        <td @if(!$tag->value) colspan="2" @endif> {{ $tag->name }}</td>
-                        @if($tag->value) <td class="tag-value">{{$tag->value}}</td> @endif
+                        <td @if(!$tag->value) colspan="2" @endif><a href="/search/all?term=%5B{{ urlencode($tag->name) }}%5D">{{ $tag->name }}</a></td>
+                        @if($tag->value) <td class="tag-value"><a href="/search/all?term=%5B{{ urlencode($tag->name) }}%3D{{ urlencode($tag->value) }}%5D">{{$tag->value}}</a></td> @endif
                     </tr>
                 @endforeach
             </table>