⭐ If you would like to buy me a coffee, well thank you very much that is mega kind! : https://www.buymeacoffee.com/honeyvig Hire a web Developer and Designer to upgrade and boost your online presence with cutting edge Technologies
Showing posts with label web. Show all posts
Showing posts with label web. Show all posts

Thursday, December 8, 2022

Multiple-user student webserver

 

For today’s (well, the last week or so) post, I’ll outline the steps needed to build a webserver that can be used by multiple users, authenticated from an active directory environment, to host content stored in individual personal directories. Last month, our existing student webserver (StudentNet) died as it was being hosted  on a disk array that was long overdue for being replaced. After 4 hard disk failures on a RAID 6 enclosure (accounting for the two hot spares that had been setup), it then died taking 10 servers down with it. Hopefully we will be able to purchase a new storage array soon – but in the meantime we need to get StudentNet back up and running for the start of term in October.

What is (or was) StudentNet?

StudentNet was a Ubuntu 12 server that was originally advertised as having the following software installed:

  • Apache
  • PHP
  • MySQL
  • Perl
  • Python
  • Firefox
  • X11
  • Oracle Java 7 (JRE and JDK)

It could be accessed internally on-campus through SSH and CIFS and finally, users could access their own directory via a web-browser by appending the url with their student ID, even externally. For now, I am only focusing on the items in bold.

Setup a basic LAMP server

First things first is to install a new VM on our ESX cluster. I recently updated the local ISOs available to the host machines to include Ubuntu 14 but I suspect that this will likely make no difference than had I stuck with using Ubuntu 12. As I have absolutely no idea of what sort of CPU load to expect, I decided to set the VM as having a single 4-core virtual CPU with 16GB of memory; it can be expanded later in the virtual machine settings. For making a new disk, I selected FFD3 – the new drive array, built from 6 (5 + 1 hot swap) 15K RPM SAS drives, collected up from no-longer (and never particularly often) used servers lying around. Like the existing SAS drives that failed they are old disks still, but most probably saw barely any use in their life (all were pillaged from other Dell servers we had around). Now, FFD3 is going to be exclusively used for studentnet – so I can allocate the entire disk group with thick provisioning to be used by the VM – if the I/O activity shreds these disks to oblivion, nothing else shares them and we can just rebuild the whole server again.

During a standard installation of Ubuntu, you can select a LAMP server as an option, but after selecting only to install OpenSSH and running a package update, I then went ahead to configure it as a LAMP server by manually installing the following:

  • apache2
  • apache2-utils
  • mysql-server
  • php-pear
  • php5
  • php5-mysql
  • php5-gd
  • php5-mcrypt
  • php5-curl
  • libapache2-mod-auth-mysql

The first thing I went ahead and did was to configure MySQL by running mysql_install_db followed by mysql_secure_installation, selecting the options to remove remote login through root and removing the test database.

I then modified /etc/apache2/mods-enabled/dir.conf to push index.php to be the preferred file (So that it now reads as “DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm_”) and did a service apache2 restart.

Finally, to test it all I created a new .php file for testing success under /var/www/html/ that just verifies mysql and php. It works!

LDAP support

I downloaded PowerBroker Identity Services from http://download.beyondtrust.com/PBISO/7.5.1.1517/linux.deb.x64/pbis-open-7.5.1.1517.linux.x86_64.deb.sh and installed it bash. I think it can probably
also be installed by running apt-get install pbis-open but I had installed 7.5 by downloading the package manually already. PBIS replaces Likewise, which used to be in the Ubuntu repository (but apparently now isn’t), and enables users to logon with active directory credentials. This means that students can now, hopefully, log in with their student IDs.

However, to do this, first we need to join the server to Active Directory by using the /opt/pbis/bin/domainjoin-cli command with the format of

“OU=<folder>,DC=<Our university>,DC=ac,DC=uk” ouruni.ac.uk serviceaccountforad

(you don’t need to add the domain to the account name). PBIS prompts you for the password and, after this, the errors started (albeit usually with no descriptions).

Now to change the PBIS configuration defaults for users logging on (so, which directory is created for them etc)

 sudo /opt/pbis/bin/lwsm refresh lsass
 sudo /opt/pbis/bin/config AssumeDefaultDomain true
 sudo /opt/pbis/bin/config HomeDirUmask 072
 sudo /opt/pbis/bin/config Local_LoginShellTemplate /bin/bash
 sudo /opt/pbis/bin/config Local_HomeDirTemplate %H/%D/%U
 sudo /opt/pbis/bin/config LoginShellTemplate /bin/bash
 sudo /opt/pbis/bin/config HomeDirTemplate %H/%D/%U
  [which represent Homedirectory/Domainname/Username]
 sudo /opt/pbis/bin/config UserDomainPrefix UOB 
 [Prefixes users and groups with UOB]
 [This restricts who can use the system, but wont use it for now. In future we might.]
 sudo /opt/pbis/bin/config RequireMembershipOf "UOB\\allStudents" "UOB\\CSTLinuxServerAdmins" "UOB\\allStaff"

I then added the Linux Server Admins group to the list of super users by running VISUDO and appending it with this like at the bottom

%CSTLinuxServerAdmins ALL=(ALL) ALL

Now, any user in that group can make system changes. Only a few people should be allowed to do this though! For a bit more security, I edited /etc/login.defs to change UMASK to 072 from 022. This means that now, nobody except people outside the group can read data and nobody except the owner can modify it.

After restarting the server, it is still joined to the domain and I can successfully log in as either a staff member or student!

 

Enabling user directories

So it seems that to get what we want, user-specific web folders, we have to use “userdir”. If I type “a2enmod userdir” to enable the module, and restart the apache2 service, I now should be able to login with WinSCP, right?

Right! I have my own directory specified as /home/UOB/(my username)/, however I can also browse other directories outside of /home/, which needs to be secured sometime. After making the changes below to /etc/apache2/mods-enabled/userdir.conf, users can put all of their files into a folder in their home directory named /public_html/ and access them through a browser at http://<server>.ac.uk/~<username/. Without the following changes, users who try to view the page will get a message that they are forbidden from being able to do so.

<Directory /home/UOB/*/public_html>
   AllowOverride All
   Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
   <Limit GET POST OPTIONS>
      #Pre-Apache 2.4
      #Order allow,deny
      #Allow from all
      Require all granted
   </Limit>
   <LimitExcept GET POST OPTIONS>
      #Pre-Apache 2.4
      #Order deny,allow
      #Deny from all
      Require all denied
   </LimitExcept>
 </Directory>

And with that (on default Ubuntu 14 installations, it is just really two changes as highlighted), we now have a working student webserver!

Next time, I will probably try and get user directories working with Samba in Windows, so that users can drive map to their area on studentnet – but this will likely make them re-use it again as a storage area where they will inevitably run files from again, creating the huge I/O activity we saw before. But we will see how students need and use it over the coming months.

Troubleshooting

  • To test if the server is in AD, I just run “pbis status”. I have found servers that have somehow “lost” their AD binding, you can just then use “/opt/pbis/bin/domainjoin-cli join” to rejoin the domain and restore AD connectivity. You can also check the config file by doing “/opt/pbis/bin/config –dump” and seeing if the settings match up as above. This might also be /opt/likewise/bin/lwconfig instead, for older installations that used Likewise before PB took over.
  • Sometimes the server may not join if the computer has been moved from its original OU to another one. To remedy this, I went into the Active Directory tree structure and deleted the computer account on the domain controller. I then attempted to rejoin the server with a success.

Bootnote: I had originally used “pbis join” as the command to join the domain. However there seems to be actually nowhere on the internet at the time of writing that specifies “pbis join” as being a command to use! It might be possible to use this instead of domainjoin-cli, but there must be something that domainjoin-cli does that pbis join doesn’t.

I suspect this is to do with /etc/pam.d/common-session which pbis join doesn’t alter, but domainjoin-cli does (it adds session sufficient pam_lsass.so and session optional pam_systemd.so to the end of the file). Additionally, the syntax is a little different than if you were to use domainjoin-cli as above (error descriptions are not always forthcoming so from the small amount on the “pbis join” command, I can only assume that this isn’t fully supported by Powerbroker – yet?):

  • First of all, I had Error 40022; I forgot my AD service account password, so I had to reset it.
  • Then I had Error 40320 – LW_ERROR_LDAP_INVALID_DN_SYNTAX – I had the syntax wrong; you don’t need to have the entire OU/DC structure, just the OU as follows: “LowestFolder/NextFolder/Computers/TopOfTree”.
  • This gave me Error 40318 – LW_ERROR_LDAP_NO_SUCH_OBJECT – I had the syntax now the wrong way around; The error indicates that the OU object doesn’t exist as it was written, so it is now  “TopOfTree/Computers/NextFolder/LowestFolder”.

After correct this one last time, it now finally works using pbis join –ou “TopOfTree/Computers/NextFolder/LowestFolder” ouruni.ac.uk serviceaccountforad.

However, this actually didn’t allow me to login, even after rebooting, as any domain user. I could find them wiith “pbis find-user-by-name” and a username of someone I know and it returns a user, telling me that it can locate users. But I can’t log in as one, bizarrely. It was then that I reverted to using domainjoin-cli

Thanks, in part, to http://andys.org.uk/bits/2010/01/28/likewise-open-and-linux/

Wednesday, December 7, 2022

Multiple-user student webserver

 we have had a second catastrophic outage of our storage array which, once again, has taken Studentnet with it. However, going from my previous blog post has allowed me to get this up and running fairly quickly. In the process, I found some addendums that I would make to the original – but rather than edit it in, I thought it would be better to make a new post to explain the differences. Plus, I found a much quicker way to get it up and running..

 

Change 1: Install Linux as a LAMP server

This is really simple. Lots of things will get installed by default here; the pear, php and mysql modules all get installed with this. Selecting this and OpenSSH is all I did this time around. Straight afterward this, all that needs to be done is the original step of altering /etc/apache2/mods-enabled/dir.conf to push index.php to the start as well as an apt-get update and upgrade

Change 2: Powerbroker/Likewise installation

This time around, I used pbis 8.2, rather than 7.5. apt-get install pbis-open doesn’t work – so we need to get it from Beyondtrust’s download site manually. Over at http://download1.beyondtrust.com/Technical-Support/Downloads/PowerBroker-Identity-Services-Open-Edition/?Pass=True can be found the latest version for a given distribution; for Ubuntu, currently, this is currently located at  http://download.beyondtrust.com/PBISO/8.2.1/linux.deb.x64/pbis-open-8.2.1.2979.linux.x86_64.deb.sh which uses the Debian release.

The following commands are how I got this working:

cd /tmp
//Make a temporary directory

wget http://download.beyondtrust.com/PBISO/8.2.1/linux.deb.x64/pbis-open-8.2.1.2979.linux.x86_64.deb.sh
//Download to this directory

sudo chmod +x pbis-open-8.2.1.2979.linux.x86_64.deb.sh
//Give execution permission for this file

sudo ./pbis-open-8.2.1.2979.linux.x86_64.deb.sh
//Run the installer. Dont select legacy links, dont need it, and select yes to install now

sudo domainjoin-cli join --ou "OU=ComputerFolder,DC=company,DC=co,DC=uk" company.co.uk myaccount
//The account "myaccount" has to be able to join the domain. You'll be prompted to enter a password.

After this, the server can now accept domain logins. The only other thing to do now is to add in some AD configuration, for things like the prefix for the domain (so users don’t have to type their username@domain.. they only need to type username) as well as where their home directory is located. The following lines add entries to the PBIS configuration:

sudo /opt/pbis/bin/config UserDomainPrefix MYDOMAIN
sudo /opt/pbis/bin/config AssumeDefaultDomain true
sudo /opt/pbis/bin/config LoginShellTemplate /bin/bash 
sudo /opt/pbis/bin/config HomeDirTemplate %H/%D/%U 
sudo /opt/pbis/bin/config RequireMembershipOf "MYDOMAIN\\students" "MYDOMAIN\\staff" "UOB\\TechStaff"
sudo /opt/pbis/bin/config HomeDirUmask 072

 

Change 3: Quick permissions changes

The only next thing to do now is to ensure that “TechStaff” are able to act as admins. We can do this by adding the following, somewhere in the sudoers file (nano /etc/sudoers):

%TechStaff ALL=(ALL:ALL) ALL

TechStaff users can now do everything. Now, for the web server part, we set home directories to be only changed by their owners (and read by anyone in the group and executed by anyone else) already, but we need to change one small thing in the apache2 user directory config after making sure we have run a2enmod userdir – Inside /etc/apache2/mods-enabled/userdir.conf , the line /home/*/public_html needs to be changed to /home/domain/*/public_html – which is specified in the HomeDirTemplate above (home/domain/user – %H/%D/%D). The next line, AllowOverride, should just say All after it, too.

After restarting apache2, everything should work alright, as before. PBIS was a lot easier to install and join the domain with this time around and with the LAMP installation automated, everything was just a lot quicker to get running.

Tuesday, December 6, 2022

Feeding the frontend – displaying data with D3.js

 

It’s been a while since I’ve posted any updates about Switchy McPortface. It works just fine in my dayjob and the data can be viewed by anyone wanting to see what is plugged into what, which has been helpful in a few situations.

However, aside from a few customised tables and functions, there’s not really a lot more that I’ve done to improve functionality. What I have done, however, is embark on making a nicer frontend with some interaction. Essentially what I am aiming to do is to display all of the computers on a single webpage for a given room, roughly corresponding to the positions that they actually exist in in each room. My first thought a few years ago was to use Unity3d or C++ and OpenGL but, since I’ve already used these things before, why not try something new and use Javascript to make a web app or something?

This guide is going to go through a nicer way to display data than just using a table generated from some basic HTML in php. There’s a few libraries out there, but I thought it would be nice to get stuck into something that has some widespread use and the name Data Driven Documents sums up nicely what I’m trying to do – generate something visual based on some underlying data. D3 gives a nice way to manipulate the DOM, bind data and provide some visualisation and I felt it fit somewhere between jQuery and (other) visualisation libraries for this project. So without further ado, here is a quick rundown of one way to use d3.js to generate something prettier than a few table rows and columns!

Starting out

Because this builds on my previous work (with the desktop client now uploaded to Github), I won’t go into exactly how you get this specific data generated, or a web server set up and running. The focus here is how to interpret data with a basic web page – so hopefully you’ll already have a way to serve and process some php files.

For this project overall, I used three files:

  • index.html – the main file you’ll call when you open your browser. It’ll also contain the page styles, instead of a separate .css file, and invoke the Javascript file
  • main.js – the file that will contain the scripts used that, in turn, call d3.js
  • query.php (this comes in part 2) – the file that handles the communication between your page and a database

The index and js files can sit at the web directory root of the server, or they can reside on your own machine. I’ve been using Brackets and testing this on my local machine, with php files running off a virtual machine and the concept is really simple:

  • Open index.html 
  • Load d3.js and the main.js files
  • Load in some data that represents computers
  • Create an SVG on the main page
  • Create a sub shape for that SVG for each computer

Index.html

The html landing page isn’t going to have an awful lot in it. Its primary purpose is to load the JS files, which in this case are d3.js v4 and jquery (used for simple AJAX calls later in part 2).

<html>
    <head>
        <title>Room test</title>
        <script src="https://d3js.org/d3.v4.js"></script>
        <script src="jquery-3.1.1.js"></script>       
    </head>
    <body>  
    </body>    
        <script src="main.js"></script>
</html>

Note that main.js is called after everything else; this is so that it loads after other JS libraries. You also don’t need to type out the entire <script type=”text/javascript” src=”main.js”></script> as of html5, since Javascript is the default script type now and the “type” attribute can be omitted.

main.js

This is where the main gubbins of this example resides. The gist of it is:

  • Create a blank SVG
  • Load in list of computers and a list of positions
  • Draw a new circle for each computer at its respective position
  • For fun, display the hostname for each of those computers when you hover over it with the mouse

Here’s each part broken down:

Creating a blank SVG

Once you’ve loaded the d3.js library in your index.html file, you can access d3 functions as in the example below. All it does is to create a blank SVG, appended to the body of the page, with an arbitrary width and height.

var w = 500;
var h = 450;
var svg = d3.select("body")
            .append("svg")
            .attr("width", w)
            .attr("height", h);

 

Load in computers and positions

So far so good? Next I’m just going to create two objects for a Computer and a Position, each taking some parameters to represent what they are. A computer is, for now, defined as simply a name – and this has a “place”. A position is a combination of a place number and its respective x and y coordinates. The reason these are separate is because at some point we might have different rooms or position layouts and I want to keep the computer and position data separate.

function Computer(place, hostname) {
    this.place = place;
    this.hostname = hostname;
}

function Position(place, posx, posy) {
    this.place = place;
    this.posx = posx;
    this.posy = posy;
}

var positions = [
    new Position('10', 0, 0),
    new Position('20', 80, 0),
    new Position('30', 160, 0),
    new Position('40', 240, 0),
    new Position('50', 0, 100),
    new Position('60', 80, 100),
    new Position('70', 160, 100),
    new Position('80', 240, 100)
];

var computers = [
    new Computer('10', "WS10562"),
    new Computer('20', "WS10239"),
    new Computer('50', "WS10555"),
    new Computer('60', "WS9111"),
    new Computer('70', "WS11032"),
    new Computer('40', "WS11031")
];

So here are two arrays of data for the computers and positions. The logic is that, whilst there may be any number of positions, they may not all be filled by a computer. Anyhow, this is all sort of irrelevant to D3 for now (and it could have been loaded in externally), so I’ll get on and demonstrate how you can now put something on screen.

Draw a new circle for each computer at its respective position

Very simply, I’m going through that array of computers and, for each one, I’ll add a circle at that position.

for (var x = 0; x < computers.length; x += 1) {
    
    var posIndex = positions.findIndex(y => y.place == computers[x].place);
                                        
    svg.append("svg")
        .append("circle")
        .attr("cx", positions[posIndex].posx + 30)
        .attr("cy", positions[posIndex].posy + 30)
        .attr("r", 20)
        .style("fill", "purple");

}

To match the data in the positions array up with the computers array, I need to first find the index of the correct item in positions array that corresponds with the “place” of the computer at the current index. In SQL, a left or an inner join would do what we need to do but in this example, I’m using two separate arrays of data that I need to match up.

Apparently, as of ES6, you can use findIndex. What this will do is return the index of positions where it finds a match by the function provided. Because I’m trying to match a property of an item in the array, the function needs to compare that “place” property for each item in the position array to the current computer’s “place” property. The => operator shortens the need to make that function by using y as the variable to represent the operative array item and it will return true when it is equal to the condition given.

For each of these computers, you can then append the SVG created earlier with a circle and give it the attributes for the radius, x and y coordinates (with an offset) and modify their style (which could be done in the index.html file but you can do it now too), which is just the fill colour here. This just adds some circles nested within the SVG tag that has been added to the page – nothing hugely complex, which is the great thing about D3. It is just a nice way to access the DOM and to add elements to a webpage dynamically.

It is important to note that this is not the best way to use D3. The way in which it should be done is to say you’ll add all of the elements of a given shape in one call then pass the data in – here, we’re going through the data first and then just adding one element on each iteration of the loop. There is no need to use a for loop in d3 and so what I’ve done is counter-intuitive to the way you’d normally learn it; but I’m simplifying the process of combining two arrays’ worth of data which I haven’t been able to find a nicer way to do when using D3. Besides, later it won’t be necessary; however, it was useful to figure out a nice way to make things work for now.

Display the hostname on mouse events

This is really easy to do. You first need to modify the previous code a little to look like this:

    svg.append("svg")
        .append("circle")
        .data(computers) //Add this!
        .attr("cx", positions[posIndex].posx + 30)
        .attr("cy", positions[posIndex].posy + 30)
        .attr("r", 20)
        .style("fill", "purple")
        .on("mouseover", fadein) //Mouse over event
        .on("mouseout", fadeout); //Mouse moved away event

Although it isn’t used as extensively as it will be later, the data function has been added in which is needed to provide the hostnames to each of the shapes when you mouse over them. For that to happen, two events need to be added with the on function – which are “mouseover” and “mouseout” (events that are triggered when the mouse is detected to have entered and exited the boundaries of the element in question). As much as I like the whole anonymous function thing in JS, I’m just going to call some named ones because I hate polluting what should be simple code with a bunch of ugly long functions that are more than 2 or 3 lines long.

And these are the functions you need:

var div = d3.select("body")
            .append("div")
            .attr("class", "tooltip")
            .style("opacity", 0)
            .text("");



function fadein(d, i) {
    div.transition().duration(200).style("opacity", 0.9);
    div.style("left", d3.mouse(this)[0])
	.style("top", d3.mouse(this)[1])
	.html(d.hostname);
    //console.log("fadeoin");
}

function fadeout() {
    div.transition().duration(400).style("opacity", 0);
    console.log("fadeout");
}

Here, the two functions can take two parameters passed into them by d3, which are the data and an index.The data is the element of the array used when each shape is created (although, in this case, that will always just be the first element, since only one circle is added at a time). The index will be which iteration that d3 element was created during.

I’ve also added a new div to the page up there too – that’s because, in order to have text pop up, I want to do it in a tiny floating “box”, which is really just an HTML element. As a result, changing the text is as simple as changing the html property of the object to whatever the hostname of that data object is. Note that, if you were to use a totally different dataset for this, “hostname” would have to be replaced by whatever else you would want to have displayed instead. I also have it appear at wherever the mouse is with a bit of a transition time, because that makes it look a bit swishier.

One last thing is that, to make it actually look nice, you might want to add a style just for the tooltip (hence div.tooltip) to the main html file within the <head> section somewhere:

<style>          
div.tooltip {
                position: absolute;
                text-align: center;
                width: 60px;
                height: 29px;
                padding: 2px;
                font: 12px sans-serif;
                background: green;
                border: 0px;
                border-radius: 9px;
                pointer-events: none;
		color: white;
            }
</style>

This centers the text and gives it a solid colour background with a bit of a rounded border and some padding.

Conclusion

If you’ve done it right, the result should look something like this (I’ve added both circles and rectangles here as a test and reduced the number of “computers” a bit for this example)

 

Carrying straight on from my previous post on the subject, I’m going to go through the alluded to third page to add, which is query.php and change main.js a little, too. The purpose is to swap out the hard coded arrays of data for an external data source, namely a web-based resource rather than any locally stored files using AJAX and JSON.

Query.php

What we’ve got so far are some blobs being drawn at various positions on the screen, based on the data stored in a couple of arrays. It isn’t all that exciting, but the main thing is that we have data in an array that can be visualised. The next step is then to load in that list of a computers from an external source. D3 can do things like load CSVs and JSON data in from a file, but since I’ve been using php to fetch data already from my database, I felt that it would be worth just adding a bit more code to what is already there to put that data into d3.

In another previous post I’d displayed the results of a query in a table, but what I want to do instead is to store them in JSON format. Its a data format that can be read and used by many different parsers on different platforms as well as being able to be directly read in by Javascript and interpreted as a list of objects.

Below is what you should be able to use to return and display a JSON string.

<?php 
	
	$username = "user";
	$password = "password";
	$room = $_GET['room'];

	$serverDB = "mysql:host=localhost;dbname=inventory";
	$conn = new PDO($serverDB, $username, $password);

	if ($conn->connect_error) {
		die("Connection failed: " . $conn->connect_error);
	}
		
	$getHosts = "SELECT * from hosts WHERE Room = '". $room ."'";

	$hosts = array();
	
	if ($result = $conn->query($getHostsPlaces))
	{
	while ($row = $result->fetch(PDO::FETCH_ASSOC))
		{
			$hosts[] = $row;
		}
		
	echo json_encode($hosts);
	}
	
	$result->closeCursor();
	$conn = null;

The first thing to note here is that, in this example, the request for the page will take the form of http://url/query.php?room=A001 – where “A001” would be the room you are asking to have the computers returned from. This lets me create the select statement with the room specified and return only the computers in a certain room.

I then create an array that has a new element added for each row (leftover terminology from the previous example). The syntax isn’t obvious but assinging a value to an array without specifying a key seems to be the same as array.push() in Javascript. After that, I then call json_encode and pass it the array of hosts, which serialises the data to be read in by something else later. In this instance I simply echo the data, which should be an array of data.

One last thing is that, unlike any previous examples, I try to now use PDOs. Included with most php/mysql installations of Linux, its a technology-neutral way to access most databases (although the connection string does specify that it is a MYSQL database), so in lieu of any real reason not to, I have decided to go down that route. However, one important thing I found out was that, if you don’t properly close the connection and queries when you’re done, you get internal server errors. So, whilst you didn’t have to do this with mysql(i) connections, you absolutely do have to with PDOs, which is probably a good thing.

When I call this page from my browser, what is displayed is the JSON’d data, as expected:


With that done, I can now go back to my main.js file and make some changes so that this data is read in.

main.js

jQuery and d3.json

It is at this point that the reference to the jQuery library becomes relevant. To access the jQuery object, you just have to use a $. It turns out that this is actually a legitimate variable name – but thankfully nobody else would be crazy enough to use it on its own so jQuery can use it all on its own. What it can then be used to do is to manipulate the DOM, like D3, although in a different way. But it can also be used to perform an AJAX request – used to grab data from another page via an XML HTTP Request, but with a fraction of the code. To call our query.php page and interpret the returned data as JSON, you can use the following code below.

$.ajax({
	url: "query.php?room=w004",
	dataType: "JSON",
	success: makeComputers
});

The callback function is what is invoked (with the data passed in as a parameter) when the AJAX call is successful (you can create a similar callback for a failure, too). I’ve made a function called makeComputers, where I will put all of the previous code.

Update: I have since found that there is an even simpler way, when using d3.xhr or d3.json. For this example, you can reduce the above code down to a single line and cut jQuery out completely:

d3.json("query.php?room=w004", makeComputers);

In either case, the result will be the same; makeComputers will be called when the call has completed. This is an asynchronous call, though, so any code inside makeComputers will likely happen a few milliseconds after whatever follows either call.

I’ve modified the original code from last time to be as follows:

function Computer(place, hostname) {
    this.place = place;
    this.hostname = hostname;
}
function Position(place, posx, posy) {
    this.place = place;
    this.posx = posx;
    this.posy = posy;
}

var positions = [
    new Position('1', 0, 0),
    new Position('2', 80, 0),
    new Position('3', 160, 0),
    new Position('4', 240, 0),
    new Position('5', 320, 0),
    new Position('6', 400, 0),
    new Position('7', 0, 100),
    new Position('8', 80, 100),
    new Position('9', 160, 100),
    new Position('10', 240, 100),
    new Position('11', 320, 100),
    new Position('12', 400, 100),
    new Position('13', 0, 200),
    new Position('14', 80, 200),
    new Position('15', 160, 200),
    new Position('16', 240, 200),
    new Position('17', 320, 200),
    new Position('18', 400, 200),
    new Position('19', 0, 300),
    new Position('20', 80, 300),
    new Position('21', 160, 300),
    new Position('22', 240, 300),
    new Position('23', 320, 300),
    new Position('24', 400, 300),
];

var computers = [];

var w = 450;
var h = 450;
var svge = d3.select("body")
            .append("svg")
            .attr("width", w)
            .attr("height", h);
var div = d3.select("body")
            .append("div")
            .attr("class", "tooltip")
            .style("opacity", 0)
            .text("Tooltip");

function makeComputers(jsony){
	for(var k=0; k<jsony.length; k++){
		computers.push(new Computer(k+1,jsony[k]['hostname']));
	}
	var recties = svge.selectAll("rect")
			.data(computers)
			.enter()
			.append("svg")
			.attr("data-hello", function (d,i) {return d[i]; })
			.append("rect")
			.attr("width", 30)
			.attr("height", 30)
			.attr("x", function(d,i) {var xloc = positions.findIndex(y => y.place == computers[i].place); return positions[xloc].posx +15})
			.attr("rx", 6)
			.attr("ry", 6)
			.attr("y", function(d,i) {var xloc = positions.findIndex(y => y.place == computers[i].place); return positions[xloc].posy +15})
			.style("fill", "Lavender")
			.on("mouseover", fadein)
			.on("mouseout", fadeout)
			.on("mousemove", moviemouse);
}
function fadein(d, i) {
    div.transition().duration(200).style("opacity", 0.9);
    div.style("left", d3.mouse(this)[0])
	.style("top", d3.mouse(this)[1])
	.html(d.hostname);
}
function fadeout(e) {
    div.transition().duration(400).style("opacity", 0);
}
function moviemouse(e) {
    div.style("left", d3.mouse(this)[0])
        .style("top", d3.mouse(this)[1]);
}

d3.json("query.php?room=w004", makeComputers);

Just to break this down in summary:

  • The makeComputers function starts off by adding all of the computers imported to the computers array based on their hostname
  • It then adds in rectangles, with the mouse listeners, using the better D3 method of adding SVGs to the page.
  • I’ve also used the findIndex function without needing a for loop, since D3 provides the index to be able to do this.
  • There are no longer any computers specified in the array of computers
  • There are now three functions associated with fading in/out and movement of the mouse (so the position of the tooltip box will change as the mouse moves)
  • Finally, this all happens when I call makeComputers at the end as the function that is executed once the request to the given URL has completed

The only last modification you may need to make, if your query.php file is stored on a different server to the one you are running your index.html and main.js from, is to add this to the top of your query.php file:

<?php 
 header("Access-Control-Allow-Origin: *");

This allows calls from other domains to be made, which is disabled by default for security reasons. However, if you’re confident that (for testing purposes at least) this won’t be an issue, then you can go ahead and enable to it, which lets you do things like run your index.html page and JS files from your local disk and make queries to the remote server.

This should have hopefully got you to a stage where you can make requests for JSON data to a web server and have it return some SQL results as readable data by JavaScript, but if anyone has any issues or encounters any oddities, do get in touch!

 

Ok so this is a bolt-on post to my previous post, where I am now essentially trying to figure out a nice way to map the data between the computers and their positions in a room. The way I’ve designed the system is that I have three tables with the relevant data:

  • Hosts: The main piece of data here is the hostname and other data – but it also contains the room that the host belongs to (and the “place”, which is just a notional number that I placed on a diagram)
  • Rooms: This is the list of rooms and their “layout type”. We could have ten different rooms each with the same layout, so this is a way to say which room has which layout type. Its sole purpose is to join the other two tables.
  • Places: The combination of a layout type and a position will give you an x and a y coordinate. This is a relative coordinate. It doesnt have to know which rooms are associated with it, its purely data on where – for a given layout type – a “position” would exist.

The idea for this is that you would fetch the respective coordinates for a host from the places table. The hosts table only has the place, so its necessary to fetch the correct layout type that matches the room, and then fetch the coordinates based on that data.

Complicated? A little. Especially for something that doesn’t seem too big. But I want it to be scalable and to separate out the data for positions from the hosts; a room may entirely change its layout but, so long as the room doesn’t change, the only thing I would need to change is the layout type and then the coordinates. However, I could have just placed all of this data into the hosts table – or removed the third table for places and just have mapped each room directly to sets of coordinates (and I still may!).

But I did find a solution, although it took a few iterations. I needed to refresh myself on inner and left joins a bit but my original plan was to do a left join between the hosts table and places table where the hosts’ room is a specific room. But then the places table works on layout type and noot a room number.

Ok so the first step would be something like this:

SELECT hostname, place, room, posx, posy
FROM hosts
INNER JOIN places ON places.position = hosts.place 

WHERE room = "W004"

Select the hostname from hosts, the coordinates from places, the room and the place from the inner join’d josts and places. The inner join will be done where the position field from places matches the place field from hosts. To limit it, I then just put “where room = w004”.

This would return a lot of results, since there’s many hosts potentially with the same place and many places with the same position. The “where” limitation narrows the hosts down to only the selection relevant to the one room, but it still leaves lots of entries potentially from the position, since there will likely be n times as many results as there are positions and layouts. That would then give duplicate host results, a duplicate for each recurring position that appears in the places table.

So the next step is to narrow this further, which was causing me a lot of headaches. I had an idea to expand the “WHERE” statement to include the room, but that isn’t a part of the dataset constructed by the joins. The solution was to do two joins – the second join being where the layout type matches the room specified in the room table and where the room matches in both the room and hosts table. This narrows both the hosts and rooms down to just one room, which means in turn there will only be one layout – and this further restricts the results from places down to what I need.

SELECT hostname, place, rooms.room, posx, posy 
FROM hosts 
INNER JOIN places ON places.position = hosts.place
INNER JOIN rooms ON rooms.room = hosts.room AND rooms.layoutType = places.layout 

WHERE rooms.room = "W004"

Note that I could have used left joins, which would preserve all the host data, but I am trying to narrow it down and there’s just no need for anything else. I should probably also tidy up some of the names a bit, especially since there is now ambiguity between the different “room”s, but not between place and position.

With that done, I can now replace my original SQL statement:

$getHosts = "SELECT * from hosts WHERE Room = '". $room ."'";

With the following:

$getHosts = "SELECT hostname, place, rooms.room, posx, posy FROM hosts INNER JOIN places ON hosts.place = places.position INNER JOIN rooms ON rooms.room = hosts.room AND rooms.layoutType = places.layout WHERE rooms.room = '". $room ."'";

A lot longer, but it returns a single dataset with all the position data we need for a given room!

Sunday, July 22, 2012

It’s Time To Stop Blaming Internet Explorer

Articles like this frustrate me a lot. For most of my career, I’ve fought hard against the “woe is me” attitude embraced by so many in Web development and articulated in the article. This attitude is completely counterproductive and frequently inaccurately described. Everyone was complaining when Internet Explorer 6 had a 90%+ marketshare. That share has shrunk to 6.3% today globally (though Louis cites 0.66%, which is true in the United States). Microsoft even kicked off a campaign to encourage people to upgrade.
I can understand complaining about Internet Explorer 6 and even 7. We had them for a long time, they were a source of frustration, and I get that. I would still never let anyone that I worked with get too buried in complaining about them. If it’s our job to support those browsers then that’s just part of our job. The truth is that every job has some part of it that sucks. Even at my favorite job, as front end lead on the Yahoo homepage, there were still parts of my job that sucked. You just need to focus on the good parts so you can tolerate the bad ones. Welcome to life.
But then the article goes on to bemoan the fact that so many people use Internet Explorer 8 and that Internet Explorer 9 is gaining market share. First and foremost, I would much rather support Internet Explorer 8 then I would 6 and 7. Microsoft forcing most people to upgrade from 6 and 7 to 8 is an incredible move and undoubtedly a blessing.

Internet Explorer 9

Internet Explorer 9, on the other hand, is a damn good browser. The only reason it doesn’t have all of the features as Chrome and Firefox is because they rebuilt the thing from scratch so that adding more features in the future would be easier. Let me say that again: they rebuilt the browser from scratch. They necessarily had to decide what were the most important features to get in so that they could release something and start getting people to upgrade from version 8. If they had waited for feature parity with Chrome or Firefox, we probably still wouldn’t have Internet Explorer 9.
The constant drumming of “Internet Explorer X is the new Internet Explorer 6″ is getting very old. Microsoft has done a lot to try to correct their past transgressions, and it seems like there are still too many people who aren’t willing to let go of old grudges. There will always be a browser that lags behind others. First it was Mosaic that was lagging behind Netscape. Then it was Netscape lagging behind Internet Explorer. Then it was Internet Explorer lagging behind Firefox. People are already starting to complain about Android 2.x browsers.
What makes the Web beautiful is precisely that there are multiple browsers and, if you build things correctly, your sites and applications work in them all. They might not necessarily work exactly the same in them all, but they should still be able to work. There is absolutely nothing preventing you from using new features in your Web applications, that’s what progressive enhancement is all about. No one is saying you can’t use RGBA. No one is holding a gun to your head and saying don’t use CSS animations. As an engineer on the Web application you get to make decisions every single day.

Progressive Enhancement

Louis briefly mentions progressive enhancement as a concept that doesn’t even enter into the equation. Once again, this is indicative of an old attitude of Web development that is counterproductive and ultimately lacking in creativity. The reason that I still give talks about progressive enhancement is because it allows you to give the best experience possible to users based on the browser’s capabilities. That’s the way the Web was meant to work. I’ve included a video of that talk below in case you haven’t seen it.
It’s not actually old browsers that are holding back the web, it’s old ways of thinking about the Web that are holding back the Web. Fixating on circumstances that you can’t change isn’t a recipe for success. The number of browsers we have to support, even “old browsers”, just represent constraints to the problems that we have to solve. It is from within constraints that creativity is born. The Web development community has evolved enough that we should stop pointing fingers at Internet Explorer and start taking responsibility for how we do our jobs. Let’s create solutions rather than continually pointing fingers. We are better than that.
Yes, complaining is useful to get people to listen. Microsoft is listening, so continuing to complain doesn’t do anything except perpetuate an attitude that I would rather not have in Web development. Let’s give them a chance to right the ship without retrying them for past transgressions perpetually.

Friday, December 9, 2011

Clear Indications That It’s Time To Redesign

Redesign. The word itself can send shudders down the spines of any Web designer and developer. For many designers and website owners, the imminent onslaught of endless review cycles, coupled with an infinite number of “stakeholders” and their inevitable “opinions,” would drive them to shave their heads with a cheese grater if given a choice between the two. Despite these realities, redesigns are a fact of any online property’s life cycle. Here are five key indications that it’s time to redesign your website and of how extensive that redesign needs to be.

Metrics Are Down

The first and most important indicator that your website is in need of a rethink is metrics that are beginning to tank. There certainly could be other reasons for this symptom (such as your product not fitting the market), but once those are eliminated or mitigated, a constant downward trend in conversions, sales, engagement activities and general user participation indicates that the efficacy of your current design has worn off. Many people call it “creative fatigue,” but what this really indicates is a disconnect with your audience. The key to solving this in the redesign is to figure out where in the workflow the design is breaking down and then address those areas as top priorities.
Metrics
The metrics are the most important indicator.
The extent to which you redesign to solve sagging metrics could be limited either to adjusting your conversion funnel, if that’s where the problem resides, or to optimizing the product’s main workflow. It does not necessarily mean having to rethink the entire face that your product presents to the world.

Your Users Tell You It’s Time

Metrics give you immediate insight that something is wrong, but to get to the core of what needs to be addressed in the redesign you need to speak with your customers. Surveys work well, but usability testing is most effective. The fluidity of face-to-face conversation allows you to explore the dynamic threads that surveys restrict. If through these conversations you notice consistent patterns that shed light on the drivers behind your downward-trending metrics (and you will), then it’s time to redesign. In addition, these user conversations will reveal prevalent attitudes towards your brand, which can also be addressed in the redesign. In some instances, negative brand perception should be enough to trigger a redesign — but you’d never know about it unless you talk to your customers.

The final decisions are still up to you. (Image: Kristian Bjornard)
Customer feedback will tell you not only whether to rethink parts of your website, but to what extent. Typically, customer conversations focus on specific elements of your workflow. Those areas are the ones that the redesign should focus on. In most cases, this wouldn’t be the whole website, but if the feedback is broad and far-reaching, then tackling the entire experience may be a priority.

The Tech/UX “Debt” List Is Longer Than Your Forearm

Over the course of building a product or website, an organization begins to accrue tech and UX debt. This debt is made up of all the things you should have done during the initial build but either didn’t get around to or had to cut corners on in order to ship the product on time. Each subsequent iteration inevitably adds more debt to the list, until the list becomes so long that it is almost insurmountable. While there are many ways to tackle tech and UX debt on an incremental level, there comes a point when the website, in essence, becomes “totalled.” Like a car that has sustained damage greater in cost than its value, your website gets to the point where starting over would be cheaper than fixing all of the items on your debt list. This is a perfect time for a redesign.
When the debt list gets this long, taking on “incremental redesigns” is easy, where you knock off bits from the list but not the majority of it. This turns into death by a thousand paper cuts, because as you fix elements on the list, you start to accrue more debt around other features. If the list truly is longer than your forearm, then rethink the website if possible.

It Just “Looks” Old

The website’s aesthetic reflects directly on the perception and trustworthiness of your brand. Even if your design was the hotness when it first launched, aesthetics evolve. An old design will be detrimental to your product, leading to the declining metrics mentioned earlier. How can you tell whether your website’s aesthetic is outdated? Look at your competition. Look at hyped-up newly launched services in other sectors. Compare your aesthetics to those of brands that are performing well. Those factors provide excellent barometers by which to assess the currency of your design. The challenge is to review these other websites objectively. Living with your website day in and day out can amplify the feeling that it’s stale and old. Ensure that your assessment is accurate by reviewing your findings with a cross-section of employees in your company.
Win some, Lose some.
Decide on what to lose and what to add. (Image: Kristian Bjornard)
In this case, the redesign would essentially be a facelift, a superficial upgrade of the presentation layer that doesn’t necessarily address the fundamental workflow or conversion funnel — although those aspects will undoubtedly be affected by this aesthetic upgrade.

It’s Been More Than 12 Months Since Your Last Refresh

Even if none of the above indicators apply to your website, the shelf life of an aesthetic in today’s highly iterative online reality is hardly ever more than 12 months. If it’s been a year or longer since you last redesigned your website, then it’s time to redesign. Not only will it refresh the experience for your loyal customers, it will attract new ones. In addition, it will breathe life into the brand and show your user base, the press, your investors and staff that you’re committed to keeping the experience fresh and top of mind.
Again, the focus here is on an aesthetic improvement that keeps the brand current, not necessarily an overhaul.

In Conclusion

These are five simple indicators that it’s likely time to redesign your website, but the list is certainly not exhaustive. The number of them that apply to your situation will determine whether a redesign is imperative. But each indicator on its own is still a strong reason to kick off the next phase of your website’s life. Maintaining a current and fresh face for the online world will yield dividends in customer acquisition, conversion and retention. Also, your staff will stay immersed in the latest technologies, design trends and presentation-layer wizardry if they know that they’ll soon get to exercise their chops in a redesign.
What indicators have you found work best in your organization to drive a website redesign?

Saturday, October 22, 2011

4 People You Should Ask For Website Feedback



Most people know that good feedback is essential to designing and developing quality websites.
But what constitutes “feedback” can be ambiguous: for some, it is little more than a hasty spell-check; for others, it is akin to submitting and defending a PhD dissertation.
While there is no one-size-fits-all solution for those seeking feedback on their work, there are some proven ways to get helpful input from others.
Here are a few ideas and tools to assist you in your quest for an improved product.
Have more ideas? Please share them in the comments area.

1. Ask Your Mom

I’m serious. Better yet, ask your grandma. Heck, even your plumber would be great! The reason I say this is because you must have people review your website who aren’t part of the web design and development community. Too often, web designers design for their industry colleagues and not for the audiences that their clients are trying to reach.
If you really want quality feedback, go a step further. For every project, try to get feedback from actual members of the audience you are trying to reach. If you are building a website for engineers, talk to engineers. If you are designing for a school, talk to teachers and students.
Admittedly, getting actionable feedback from outside the web design community can be hard (see “How a Web Design Goes Straight to Hell“), but at the very least, these groups might alert you to mistakes you’ve made from misunderstanding the target audience.
A lot is to be said for thinking on your own about an audience’s online habits and aesthetic preferences. But as fruitful as that can be, do it only after you’ve stepped out of your ivory tower and mingled with the Internet’s common folk.

2. Ask a Big Name

Here’s a question: if you could get feedback from anyone in the world, who would it be?
Every person would choose someone different, but I’ll bet almost everyone could whip up a shortlist of people who they would love to bounce a few questions off of. Here’s the more important question: what’s stopping you from asking them? Sure, they may be busy and important, but that doesn’t mean trying to reach them isn’t worth a shot.
I don’t meant to brag, but I’ve been able to get just about everyone I’ve approached to reply to an email or talk by phone for five minutes to discuss a few questions. Sure, it took some digging and out-of-the-box thinking on my part (as well as being extra nice to their personal assistants or secretaries!), but it was well worth it. You would be surprised how accessible such people can be if you show genuine (but not creepy) interest and respect for their time.
Tim Ferris has an excellent section in his book The Four-Hour Work Week and in a post on his blog about reaching out to big names to discuss ideas and ask questions. In the section of his book entitled “Find Yoda,” Ferris gives a few tips for getting big name mentors on the phone (the one he mentions from his own experience is author John Grisham).
Not everyone can do this, but that’s the point: only the most innovative, persistent and courageous will follow through on getting feedback from their heroes, and that is ultimately what sets them apart from the crowd.

3. Ask Yourself

Here’s a seemingly obvious one. You are surely already editing your own work and making adjustments as needed. But are you really stepping back and asking yourself deep critical questions about your work (questions that would likely lead to revisions), or are you coasting on what you think looks good at the moment?
Every designer and developer would do well, upon completing a project, to wait before submitting it to the client. Get as far away from it as you can for a day or two, and then come back to it with fresh eyes.
Waiting until that heat of the moment has passed will uncover problems that you missed earlier or perhaps give you new confidence in elements you weren’t sure about before. Either way, taking a step back and asking yourself critical questions will give you a more thoughtful, deliberate piece of work.

4. Ask Your Community

Whether you work alone or with a team of designers and developers, you need feedback from people who are like you and who do the same kind of work you do.
The feedback you get from fellow members of the community is the most actionable because they know the vocabulary and can give you hard, practical advice (instead of the dreaded verdict one gets from clients, “It needs a bit more pizzazz!”). Your community also understands the various factors that affect your work, like budgets, deadlines and stressful clients.
If you are a freelancer or work alone, getting feedback from the wider community can be frustrating, because you don’t have a dedicated team of colleagues who can review what you’re doing. You’re not alone in this (think of the thousands of other freelancers out there), but there are a few ways to work the situation to your advantage.
One way is to trade feedback. Find a web designer or developer whom you respect, and offer to review their next project in exchange for their feedback on yours (you might not even know them personally—but don’t let that stop you!). Figuring out a system for giving and receiving feedback might take a while, but such a relationship has the potential to become beneficial and second-nature for both of you.

Tools for Collecting Feedback

Most websites, with their forums and comment sections, aren’t ideal places to collect and aggregate feedback. Here instead are a few innovative tools that provide great ways to share and receive feedback on projects and designs.
Concept Feedback - Website Review Community
Concept Feedback is a growing community of design, development and marketing professionals and a welcome change to disorganized forum walls. Concept Feedback allows others to provide quick, actionable feedback on your website via a comprehensive rating system, with the requirement that everyone first give quality feedback before receiving feedback from others. Oh, did I mention that it’s free?

Usabilla
Usabilla allows you to collect feedback for any web page, mock-up, sketch or image. Participants (who you are responsible for finding) simply point and click to share their opinions. Paid plans start at $49 per year, but you can start with five pages for free.

Feedback Army
Feedback Army lets you pose specific questions to a panel of reviewers about anything related to your website. This tool is very helpful for seeing the reactions of others to your website’s particular processes (such as placing an order or signing up for an account). Ten different responses will cost you $10. (UserTesting.com provides a similar service.)

Creattica
Creattica brings together a group of top-notch designers looking to share a wide range of design projects. Membership and participation is free, but feedback is limited to labeling items as “favorites.”

Five Second Test
Five Second Test invites random people to look at your website for five seconds and then give feedback on what they remember of the design and other “prominent elements of your user interface.” Probably not the best tool for in-depth analysis of your work, but a great one to gauge first impressions. Free and paid plans (starting at $4) are available.

Notable App
Notable is a collaborative feedback tool for web designers (similar to ConceptShare and ProofHQ). The free plan includes up to three users, but you’re on your own for finding willing subjects.

Please Critique Me
Please Critique Me is where a panel of web design experts picks out websites from among user submissions to give extensive feedback. They can’t provide criticism to everyone, but submitting your work is certainly worth a shot.

Creating Quality Work

A good web design rarely just happens. It is refined over time by having others (and occasionally you yourself) do everything from kicking the tires to taking it for a full test drive.
Putting aside your ego and opening up to criticism might be hard at first, but feedback from others combined with your creativity make for an excellent product that you and your clients will be proud of.

10+ WordPress comment management plugins

Not everyone wants to manage a third-party comment system. And those are the users who will find the comment plugins below really useful.
Below are eleven plugins that can handle everything from adding tweets about your posts to your comments section to stripping out potentially malicious code to preventing spam comments.
There are also plugins that help increase user engagement and usability for your commenters. Let us know in the comments what your favorite comment-related WP plugins are, whether they made the list or not!

1. Twitter Mentions as Comments

As social media continues to grow, a lot of conversations surrounding blog content aren’t happening on the originating blogs. They’re happening on Twitter, Facebook, Google+, and elsewhere. And while it’s great to have people sharing and discussing your content with their social networks, it can sometimes make your blog comments section look anemic.
Twitter Mentions as Comments brings the conversation from Twitter back to your blog. It uses Twitter’s search API to find people linking to your posts and then inserts their tweets alongside your comments (using your blog’s existing comment filters), effectively making Twitter an extension of your blog.


2. WTC Comment Cleaner

This plugin strips potentially malicious code from your blog comments. Just specify what tags you want to allow, and WTC Comment Cleaner will remove all other tags, enhancing security on your blog. It’s currently compatible up through WP 3.2.1.

3. Comment Timeout

Comment Timeout closes comments on posts after a configurable period of time. But in addition to that, you can customize it to allow the open discussion period to extend beyond the default settings if there are recent approved comments on a post, or override comment closing on a post-by-post basis. This way, if there’s still an active discussion surrounding a post, comments can be left open indefinitely.

4. Impostercide

A lot of blogs opt to hold any comments for moderation until a user has had at least one comment approved. And that’s a great idea until some spammer figures out the email address of someone with an approved comment on your blog and overrides your moderation policy by entering an inauthentic email address. Impostercide solves this problem by preventing unauthenticated users from posting a comment with a registered user’s email address.


5. Sticky Comments

Sticky posts have been around in WP for quite awhile, either accomplished by plugins or themes. But what about Sticky Comments? Maybe you want to put a comment you’ve written yourself at the top of your comments list to further clarify something. Or maybe a regular commenter on your blog has provided some kind of valuable insight. This plugin lets you make their comment sticky, so it sits at the top of the comments list. It also lets you re-order comments to either newest first or oldest first.


6. Live Comment Preview

Live Comment Preview lets a visitor see how their comment will appear as they type into the comment box. It uses client-side JavaScript only (not Ajax), and even strips disallowed HTML tags from the comment in the preview. No configuration is required.


7. Minimum Comment Length

How sick are you of getting one- or two-word comments on your blog? “Thanks” or “Great post” do nothing to add to the conversation and can even make your blog look spammy. Minimum Comment Length can prevent those kinds of comments and require your commenters to leave something a bit more substantial. If they leave a comment that’s too short, WordPress will give them a friendly error message letting them know that, and asking them to leave something more useful.


8. Conditional CAPTCHA

CAPTCHA codes, while useful for spam filtering, are a big usability issue. At the same time, though, on blogs with tons of comments, it can be the most effective way to weed out spam. Conditional CAPTCHA helps solve that problem. If a comment is potentially spam (based on either Akismet or TypePad AntiSpam), the commenter will be shown a CAPTCHA code. If they don’t enter it correctly, their comment is automatically discarded or trashed, keeping your spam queue less cluttered. If they do enter it correctly, you can choose to either have their comment added to the spam queue or be approved immediately.


9. One Click Close Comments

Being able to open or close comments on a post is built into WordPress. But you have to go into each individual post to do so. What if you want to close comments on a bunch of posts (or re-open them)? One Click Close Comments allows you to open or close comments right from the post listing in the dashboard.


10. Thank Me Later

It’s a nice touch to email new commenters on your blog. Thank Me Later automates the process and automatically sends an email to thank those who comment on your blog. This can help increase engagement and make your visitors feel appreciated and valued.


11. Comment E-Mail Verification

With Comment E-Mail Verification, if a comment is held for moderation, an email is sent to the comment author with a verification link. Once the link is clicked on, the comment is automatically approved, greatly reducing spam comments. It’s also possible to set the comments to be held in moderation even after the link is clicked, if you prefer to still manually verify.


Regardless of what your comment management needs are, there’s almost certainly a plugin out there that can help you.
The WordPress plugins directory alone has over 800 plugins tagged with “comments” (just make sure you check that they’re compatible with your version of WP). And that doesn’t include all the premium plugins out there.

Friday, October 21, 2011

20 Websites With Unique Layouts

When you are creating a new website you may be inspired by seeing other sites that feature unique layouts. The 20 sites listed here don’t simply use a typical two or three column layout. Many of them use background images to interact with and control the layout in some unique way. Some of them I really like, and some I’m not sold on, but all are unique in one way or another.
 Popmatik – Freelance web designer Rob Leach uses a unique layout for his portfolio site. The site uses a background image of a bottle and the content of the site appears to be on the label of the bottle.
Popmatik Screenshot
Digitalmash.com – Digital Mash is the home of Australian web designer Rob Morris. What makes the layout unique is the background image of Rob holding the content of the page.
Digital Mash Screenshot
Melissahie.com – A portfolio site with a different twist, MelissaHie.com leads the visitor through a series of different sections of one page that include links to websites in a portfolio, a brief bio, and contact information. As you click on links, you will slide to a different section of the page.
Melissahie.com Screenshot
Evanescenceuk.co.uk – The British website of American rock band Evanescence uses a horizontal layout and a navigational scheme similar to MelissaHie.com, where the visitor slides across the site when using the navigation rather than being taken to a separate page.
Evanescence Screenshot
Sitotis.hr - The background image for Sitotis is a binder that contains the content of the page. Tabs in the binder are used for navigation.
Sitotis Screenshot
Mussatto.com.br – Mussatto uses a long, horizontal layout that doesn’t require vertical scrolling as opposed to the standard, tall layout.
Mussatto Screenshot

Basil Gloo – Web Developer Basil Gloo uses an interesting layout on his homepage that separates the page into a left and a right side. The left side contains his personal information and the right side his business information.
Basil Gloo Screenshot
Danviv.net – The portfolio site of Dan Viveiros uses a unique layout and several images of cassette tapes.
Danviv.net Screenshot
CraigEarl.co.uk – Photographer Craig Earl uses a layout that features four tall and narrow images that link to different categories of photos in his portfolio: everyday, landscapes, bands, and people.
Craig Earl Screenshot
JeremyCowart.com – Another interesting photography portfolio site, JeremyCowart.com places all of the emphasis on the pictures by taking you straight to the photos in the portfolio. Rather than making you click a few links to get to the photos, they are right there, one on top of the other. What’s most unique is that to get to any content other than photos you can visit the contact, news, and project links.
JeremyCowart.com Screenshot
Huge – This design company uses a large image on the left side of the homepage with the primary navigation and content in a narrow column on the right.
HugeInc Screenshot
Interview Magazine – Another horizontal layout, Interview Magazine presents a different visual impression than other online magazines.
Interview Magazine Screenshot
The Horizontal Way – As a gallery of horizontal websites, The Horizontal Way naturally uses a horizontal layout itself.

The Horizontal Way Screenshot
Swiths.com – This website uses a large background image of a wood floor and a guy’s feet. The content of the site is on a piece of paper and a notepad laying on the floor.
Swiths Screenshot
Davor van Eijk – The homepage of Davor van Eijk places navigation in the center of the page on an angle. The content of the page is in the lower right hand corner.
Davor van Eijk Screenshot
Ribbit.com – This layout features a large background image of a man sitting on the grass. The sky in the picture becomes the background of the page. The picture and how it interacts with the layout is really what give the page a unique feel.
Ribbit Screenshot
BootB – This site uses a black background and some drawn clouds at the top of the page. The center of the page contains navigation in a circle that is part of an image of a hot air balloon that is about to float to the clouds.
BootB Screenshot
Vesess – Vesess uses a simple header that includes navigation and then goes into an image right at the focal point of the page. If you scroll down you will see the use of a few columns for some basic information. While it is maybe not as different as many of the sites on this list it is still a break from the norm.
Vesess Screenshot
Dinulovic.com – The Dinulovic homepage contains no real content. It uses an image at the center of the layout with navigation on both sides.
Dinulovic
StoryAbout.net – The homepage of Hansol Huh’s portfolio site uses a large image that says “Life is Random” in dots. Below the image is a link to the portfolio.
StoryAbout.net Screenshot

50+ Gorgeous Navigation Menus

If you’re looking to learn more about design websites, please see our post Learn Web Design for plenty of resources to help your educational pursuit.
When I’m looking at excellent websites for design inspiration, one of my favorite aspects of design to notice is the navigation menu. While I enjoy seeing excellent designs of all types (minimal to artistic to colorful to dark) and various aspects of the site (including headers and footers), a well-designed and well-executed navigation menu can have more impact on my appreciation of a site than any other single piece of the design.
In this post I’d like to take a look at more than 50 stellar examples of navigation menus that positively impact the design of a website. The list includes a great deal of variety. Regardless of what you personally prefer, there should be some inspirational examples in here for you.
Housing Works

30elm

Nuttersmark

Paiko

Good

Soh Tanaka

Matt Dempsey

Web Design Ledger

Bridge55

Rzepak Pure


Fall for Tennessee

Digitalmash

BlackBook Magazine

Thuiven

Valley Creek Church

Branded07

Kyan

Carbonica

Remedy Drive

SpaceCollective

Aten Design Group

Power to the Poster

Lift Interactive

Surfstation

Ad Fed

College Park Church

WWD

Jamie’s Italian

StyleSpion

Grooveeffect

Rockatee

Boxwish

The Resume Girl

Vitor Lourenco

Ashville School

Buffalo

Africa Tour 2008

Designsensory

Jobs on the Wall

Aptana

Stucel

MacAllen Ridge

Create and Live

The 9513

Scott Mallinson

Paolo Boccardi

Interactive

Mint

DrupalCon DC

New Song Church

45royale

Mia & Maggie