diff --git a/assets/js/modules/album.js b/assets/js/modules/album.js
index b61efc6..adb1108 100644
--- a/assets/js/modules/album.js
+++ b/assets/js/modules/album.js
@@ -96,28 +96,25 @@ album = {
 
 				title = $(".message input.text").val();
 
-				if (title==="") title = "Untitled";
+				if (title.length===0) title = "Untitled";
 
-				if (title.length>0&&title.length<31) {
+				modal.close();
 
-					modal.close();
+				params = "addAlbum&title=" + escape(encodeURI(title));
+				lychee.api(params, function(data) {
 
-					params = "addAlbum&title=" + escape(encodeURI(title));
-					lychee.api(params, function(data) {
+					if (data!==false) {
+						if (data===true) data = 1; // Avoid first album to be true
+						lychee.goto(data);
+					} else lychee.error(null, params, data);
 
-						if (data!==false) {
-							if (data===true) data = 1; // Avoid first album to be true
-							lychee.goto(data);
-						} else lychee.error(null, params, data);
-
-					});
-
-				} else loadingBar.show("error", "Title too short or too long. Please try again!");
+				});
 
 			}],
 			["Cancel", function() {}]
 		];
-		modal.show("New Album", "Please enter a title for this album: <input class='text' type='text' maxlength='30' placeholder='Title' value='Untitled'>", buttons);
+		
+		modal.show("New Album", "Enter a title for this album: <input class='text' type='text' maxlength='30' placeholder='Title' value='Untitled'>", buttons);
 
 	},
 
@@ -203,37 +200,33 @@ album = {
 
 				newTitle = ($(".message input.text").val()==="") ? "Untitled" : $(".message input.text").val();
 
-				if (newTitle.length<31) {
+				if (visible.album()) {
 
-					if (visible.album()) {
-
-						album.json.title = newTitle;
-						view.album.title();
-
-					} else if (visible.albums()) {
-					
-						albumIDs.forEach(function(id, index, array) {
-							albums.json.content[id].title = newTitle;
-							view.albums.content.title(id);
-						});
-
-					}
-
-					params = "setAlbumTitle&albumIDs=" + albumIDs + "&title=" + escape(encodeURI(newTitle));
-					lychee.api(params, function(data) {
-
-						if (data!==true) lychee.error(null, params, data);
+					album.json.title = newTitle;
+					view.album.title();
 
+				} else if (visible.albums()) {
+				
+					albumIDs.forEach(function(id, index, array) {
+						albums.json.content[id].title = newTitle;
+						view.albums.content.title(id);
 					});
 
-				} else if (newTitle.length>30) loadingBar.show("error", "New title too long. Please try another one!");
+				}
+
+				params = "setAlbumTitle&albumIDs=" + albumIDs + "&title=" + escape(encodeURI(newTitle));
+				lychee.api(params, function(data) {
+
+					if (data!==true) lychee.error(null, params, data);
+
+				});
 
 			}],
 			["Cancel", function() {}]
 		];
 		
-		if (albumIDs.length===1) modal.show("Set Title", "Please enter a new title for this album: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
-		else modal.show("Set Titles", "Please enter a title for all " + albumIDs.length + " selected album: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
+		if (albumIDs.length===1) modal.show("Set Title", "Enter a new title for this album: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
+		else modal.show("Set Titles", "Enter a title for all " + albumIDs.length + " selected album: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
 
 	},
 
@@ -249,25 +242,22 @@ album = {
 
 				description = $(".message input.text").val();
 
-				if (description.length<801) {
+				if (visible.album()) {
+					album.json.description = description;
+					view.album.description();
+				}
 
-					if (visible.album()) {
-						album.json.description = description;
-						view.album.description();
-					}
+				params = "setAlbumDescription&albumID=" + photoID + "&description=" + escape(description);
+				lychee.api(params, function(data) {
 
-					params = "setAlbumDescription&albumID=" + photoID + "&description=" + escape(description);
-					lychee.api(params, function(data) {
+					if (data!==true) lychee.error(null, params, data);
 
-						if (data!==true) lychee.error(null, params, data);
-
-					});
-
-				} else loadingBar.show("error", "Description too long. Please try again!");
+				});
 
 			}],
 			["Cancel", function() {}]
 		];
+		
 		modal.show("Set Description", "Please enter a description for this album: <input class='text' type='text' maxlength='800' placeholder='Description' value='" + oldDescription + "'>", buttons);
 
 	},
diff --git a/assets/js/modules/contextMenu.js b/assets/js/modules/contextMenu.js
index e180935..34091e6 100644
--- a/assets/js/modules/contextMenu.js
+++ b/assets/js/modules/contextMenu.js
@@ -157,6 +157,7 @@ contextMenu = {
 
 		contextMenu.fns = [
 			function() { photo.setStar([photoID]) },
+			function() { photo.editTags([photoID]) },
 			function() { photo.setTitle([photoID]) },
 			function() { contextMenu.move([photoID], e, "right") },
 			function() { photo.delete([photoID]) }
@@ -164,10 +165,11 @@ contextMenu = {
 
 		items = [
 			["<a class='icon-star'></a> Star", 0],
+			["<a class='icon-tags'></a> Tags", 1],
 			["separator", -1],
-			["<a class='icon-edit'></a> Rename", 1],
-			["<a class='icon-folder-open'></a> Move", 2],
-			["<a class='icon-trash'></a> Delete", 3]
+			["<a class='icon-edit'></a> Rename", 2],
+			["<a class='icon-folder-open'></a> Move", 3],
+			["<a class='icon-trash'></a> Delete", 4]
 		];
 
 		contextMenu.show(items, mouse_x, mouse_y, "right");
@@ -186,6 +188,7 @@ contextMenu = {
 
 		contextMenu.fns = [
 			function() { photo.setStar(photoIDs) },
+			function() { photo.editTags(photoIDs) },
 			function() { photo.setTitle(photoIDs) },
 			function() { contextMenu.move(photoIDs, e, "right") },
 			function() { photo.delete(photoIDs) }
@@ -193,10 +196,11 @@ contextMenu = {
 
 		items = [
 			["<a class='icon-star'></a> Star All", 0],
+			["<a class='icon-tags'></a> Tag All", 1],
 			["separator", -1],
-			["<a class='icon-edit'></a> Rename All", 1],
-			["<a class='icon-folder-open'></a> Move All", 2],
-			["<a class='icon-trash'></a> Delete All", 3]
+			["<a class='icon-edit'></a> Rename All", 2],
+			["<a class='icon-folder-open'></a> Move All", 3],
+			["<a class='icon-trash'></a> Delete All", 4]
 		];
 
 		contextMenu.show(items, mouse_x, mouse_y, "right");
diff --git a/assets/js/modules/photo.js b/assets/js/modules/photo.js
index e506fe1..2d05847 100644
--- a/assets/js/modules/photo.js
+++ b/assets/js/modules/photo.js
@@ -146,33 +146,29 @@ photo = {
 
 				newTitle = $(".message input.text").val();
 
-				if (newTitle.length<31) {
+				if (visible.photo()) {
+					photo.json.title = (newTitle==="") ? "Untitled" : newTitle;
+					view.photo.title();
+				}
 
-					if (visible.photo()) {
-						photo.json.title = (newTitle==="") ? "Untitled" : newTitle;
-						view.photo.title();
-					}
+				photoIDs.forEach(function(id, index, array) {
+					album.json.content[id].title = newTitle;
+					view.album.content.title(id);
+				});
 
-					photoIDs.forEach(function(id, index, array) {
-						album.json.content[id].title = newTitle;
-						view.album.content.title(id);
-					});
+				params = "setPhotoTitle&photoIDs=" + photoIDs + "&title=" + escape(encodeURI(newTitle));
+				lychee.api(params, function(data) {
 
-					params = "setPhotoTitle&photoIDs=" + photoIDs + "&title=" + escape(encodeURI(newTitle));
-					lychee.api(params, function(data) {
+					if (data!==true) lychee.error(null, params, data);
 
-						if (data!==true) lychee.error(null, params, data);
-
-					});
-
-				} else if (newTitle.length>30) loadingBar.show("error", "New title too long. Please try another one!");
+				});
 
 			}],
 			["Cancel", function() {}]
 		];
 
-		if (photoIDs.length===1) modal.show("Set Title", "Please enter a new title for this photo: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
-		else modal.show("Set Titles", "Please enter a title for all " + photoIDs.length + " selected photos: <input class='text' type='text' maxlength='30' placeholder='Title' value=''>", buttons);
+		if (photoIDs.length===1) modal.show("Set Title", "Enter a new title for this photo: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
+		else modal.show("Set Titles", "Enter a title for all " + photoIDs.length + " selected photos: <input class='text' type='text' maxlength='30' placeholder='Title' value=''>", buttons);
 
 	},
 
@@ -280,49 +276,62 @@ photo = {
 
 				description = $(".message input.text").val();
 
-				if (description.length<800) {
+				if (visible.photo()) {
+					photo.json.description = description;
+					view.photo.description();
+				}
 
-					if (visible.photo()) {
-						photo.json.description = description;
-						view.photo.description();
-					}
+				params = "setPhotoDescription&photoID=" + photoID + "&description=" + escape(description);
+				lychee.api(params, function(data) {
 
-					params = "setPhotoDescription&photoID=" + photoID + "&description=" + escape(description);
-					lychee.api(params, function(data) {
+					if (data!==true) lychee.error(null, params, data);
 
-						if (data!==true) lychee.error(null, params, data);
-
-					});
-
-				} else loadingBar.show("error", "Description too long. Please try again!");
+				});
 
 			}],
 			["Cancel", function() {}]
 		];
-		modal.show("Set Description", "Please enter a description for this photo: <input class='text' type='text' maxlength='800' placeholder='Description' value='" + oldDescription + "'>", buttons);
+		
+		modal.show("Set Description", "Enter a description for this photo: <input class='text' type='text' maxlength='800' placeholder='Description' value='" + oldDescription + "'>", buttons);
 
 	},
 	
 	editTags: function(photoIDs) {
 	
-		var oldTags = "";
+		var oldTags = "",
+			tags = "";
 	
 		if (!photoIDs) return false;
 		if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
-		if (visible.photo()) oldTags = photo.json.tags.replace(/,/g, ', ');
+		
+		// Get tags
+		if (visible.photo()) oldTags = photo.json.tags;
+		if (visible.album()&&photoIDs.length===1) oldTags = album.json.content[photoIDs].tags;
+		if (visible.album()&&photoIDs.length>1) {
+			var same = true;
+			photoIDs.forEach(function(id, index, array) {
+				if(album.json.content[id].tags===album.json.content[photoIDs[0]].tags&&same===true) same = true;
+				else same = false;
+			});
+			if (same) oldTags = album.json.content[photoIDs[0]].tags;
+		}
+		
+		// Improve tags
+		oldTags = oldTags.replace(/,/g, ', ');
 	
 		buttons = [
 			["Set Tags", function() {
 
 				tags = $(".message input.text").val();
 
-				if (tags.length<800) photo.setTags(photoIDs, tags)
-				else loadingBar.show("error", "Description too long. Please try again!");
+				photo.setTags(photoIDs, tags);
 
 			}],
 			["Cancel", function() {}]
 		];
-		modal.show("Set Tags", "Please enter your tags for this photo. You can add multiple tags by separating them with a comma: <input class='text' type='text' maxlength='800' placeholder='Tags' value='" + oldTags + "'>", buttons);
+		
+		if (photoIDs.length===1) modal.show("Set Tags", "Enter your tags for this photo. You can add multiple tags by separating them with a comma: <input class='text' type='text' maxlength='800' placeholder='Tags' value='" + oldTags + "'>", buttons);
+		else modal.show("Set Tags", "Enter your tags for all " + photoIDs.length + " selected photos. Existing tags will be overwritten. You can add multiple tags by separating them with a comma: <input class='text' type='text' maxlength='800' placeholder='Tags' value='" + oldTags + "'>", buttons);
 	
 	},
 	
@@ -342,6 +351,10 @@ photo = {
 			view.photo.tags();
 		}
 		
+		photoIDs.forEach(function(id, index, array) {
+			album.json.content[id].tags = tags;
+		});
+		
 		params = "setTags&photoIDs=" + photoIDs + "&tags=" + tags;
 		lychee.api(params, function(data) {
 
diff --git a/php/modules/album.php b/php/modules/album.php
index 67e3e6b..133d247 100755
--- a/php/modules/album.php
+++ b/php/modules/album.php
@@ -115,15 +115,15 @@ function getAlbum($albumID) {
 	switch($albumID) {
 
 	    case "f":	$return['public'] = false;
-	    			$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE star = 1 " . $settings['sorting'];
+	    			$query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE star = 1 " . $settings['sorting'];
 	        		break;
 
 	    case "s":	$return['public'] = false;
-	    			$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE public = 1 " . $settings['sorting'];
+	    			$query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE public = 1 " . $settings['sorting'];
 	        		break;
 
 	    case "0":	$return['public'] = false;
-	    			$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = 0 " . $settings['sorting'];
+	    			$query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = 0 " . $settings['sorting'];
 					break;
 
 	    default:	$result = $database->query("SELECT * FROM lychee_albums WHERE id = '$albumID';");
@@ -134,7 +134,7 @@ function getAlbum($albumID) {
 			    	$return['public'] = $row->public;
 			    	if ($row->password=="") $return['password'] = false;
 			    	else $return['password'] = true;
-			    	$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = '$albumID' " . $settings['sorting'];
+			    	$query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = '$albumID' " . $settings['sorting'];
 			    	break;
 
 	}
@@ -150,6 +150,7 @@ function getAlbum($albumID) {
 	    $return['content'][$row['id']]['sysdate'] = date('d F Y', strtotime($row['sysdate']));
 	    $return['content'][$row['id']]['public'] = $row['public'];
 	    $return['content'][$row['id']]['star'] = $row['star'];
+	    $return['content'][$row['id']]['tags'] = $row['tags'];
 	    $return['content'][$row['id']]['album'] = $row['album'];
 	    $return['content'][$row['id']]['thumbUrl'] = $row['thumbUrl'];