Free Code Camp Intermediate Front End Development Projects

Laptop Coding

I’m going through Free Code Camps developer program and I just finished the Intermediate Front End Development Projects. I enjoy the teaching style of FCC compared to other online learning resources. It focuses more on you finding solutions and not just changing things from the examples to find an answer. Here are the four projects that I made for the Front End Development Projects.

Build a Random Quote Machine

See the Pen Random Quotes by Anthony Skelton (@ajskelton) on CodePen.

This was a fun project to get started using Ajax. After registering for the API key and getting configured I had my quotes coming in. I probably spent more time working on the design than the functionality and went through a couple different looks. I decided to go with the fade out fade in look, and got some practice chaining events by using the complete function of jQuery’s fadeOut to make sure the data didn’t change before the text had been removed.

Show the Local Weather

See the Pen Local Weather Application by Anthony Skelton (@ajskelton) on CodePen.

EDIT: This pen broke at some point, it’s on my list to fix.

My main struggle with this project was choosing what icons to display for the current weather. I looked at a bunch of options, and probably would have gone with svg icons from icomoon, but I hadn’t signed up for Codepen Pro yet so I didn’t have the ability to host any files. I could have previewed the icon font, but since that only worked for 24 hours I figured it was best to use something else.

I found a great pen from Josh Bader  with six animated weather icons in pure css. I used the codes returned from the weather api to determine which icon would be displayed.

Build a Wikipedia Viewer

See the Pen Custom Wikipedia Viewer by Anthony Skelton (@ajskelton) on CodePen.

The main problem I encountered with this project was in my Ajax call. I kept getting the “No ‘Access-Control-Allow-Origin’ header is present on the requested resource” error. After a while of hitting my head on the wall I found I need to add more header information, and declaring dataType: “jsonp” did the trick.

For the design I used the Bourbon framework and added the search results as links from the Bourbon Refills Pattern Library. I liked the way I could include a thumbnail image as well as a variable chuck of text for the results.

Use the Twitch.tv JSON API

See the Pen TwitchTV Channel Status by Anthony Skelton (@ajskelton) on CodePen.

The tricky part of this pen was dealing with a nested Ajax call. The streams api returns limited information when a channel is offline. Not even the logo is available. In my success function I first check if the stream is online. If it’s not that’s when I do a second Ajax request using the same channel name but to the channel endpoint. This gives me the logo that I need to display. Since I’m separating the online from offline channels this gives me the opportunity to append them to different container divs.

Wrapping up the Front End Development Projects

I’m now over halfway through the Intermediate algorithms in the next section of Free Code Camp. I’m learning a lot of new techniques as well as good problem solving to get through some of the complicated questions. I’ll write up more about my progress as my time with the program continues.

WordCamp Sacramento 2015

WordCamp Sacramento

This was the inaugural year of Wordcamp Sacramento.  This seemed fitting as it was also my first Wordcamp to attend. The program lineup had many interesting talks scheduled and I knew I wouldn’t have a dull moment.

I even volunteered to help out in the Happieness Bar for an hour during the day. My WordPress development has come a long way over the past couple of years. Volunteering allowed me to help others and be a part of the Sacramento community.

After picking up some new swag and attending the opening remarks it was off to the advanced track room.

0900 – Local Development with Vagrant & VVV

John Trujillo of Tytanium Ideas began the day talking about local development. He walked us trough the process of setting up a virtual machine using Vagrant. The big advantage than Jon stressed is the ability to match your local development to your server. Then you can use the version of software that your production environment is running. You can also share the setup so others in your team can quickly spin up the same local environment.

The magic of VVV

Varrying-Vagrant-Vagrants is a Vagrant environment that has been configured for WordPress Development. While Vagrant is for setting up any virtual server, VVV is built specifically to build WordPress Plugins/Themes/Apps. It includes a lot of tools out of the box

  • Ubuntu
  • nginx (apache version available)
  • 4 Standard WordPress Instals
  • WP-CLI
  • lots more!

John walked us through the process of getting all this setup on our own computer. Vagrant uses shared folders so you can create your WordPress files in your own directories and they work within the VM. You can either use phpMyAdmin, Sequl Pro (or eqv), or even SSH into your server with Vagrant  to access your VM’s database.

I’ve been using VVV for a few months so I had already gone through the process of installing and setting it up. Though most of this was review it was great to see another developer go through a similar process to setup a local development environment. John also touched on some other Vagrant projects focused on WordPress Development. The Mercury Vagrant (HGV) is built by WPEngine to match their environment. There is also Trellis which uses Ansible for provisioning a LEMP stack for WordPress.

1000 – Content Design – Getting the Most from your Content and Images

For the second talk I decided to slide over to the beginner track to see Dawn Pedersen’s talk on Content. I misread the schedule and didn’t realize that I would miss out on Vasken Hauri from 10up talk about everything Cache.

The talk began where most content begins, with the text. Writing and formatting text is important to deliver your message to the reader. Unlike a book or magazine, people rarely read a webpage word for word. We jump around and scan the page looking for things that are meaningful.

This means you should write your copy so it is scannable, and above all else, avoid the Wall of Text! Some other tips were:

  • Use the Inverted pyramid
  • Write Simply
  • Limit yourself to one idea per paragraph
  • Break texts into lists ( like this 😛 )
  • Use Headings and Subheadings
  • Highlight Keywords

The Inverted Pyramid

People will decide if they will keep reading based on the first sentence or two. So you need to get to the point first. It means they could read the first paragraph and have the broad understanding of your subject.

From here use broad strokes and then the important details. Try to flesh out your ideas in the later paragraphs. You also want to use good transitions to get from one idea to the next.

Write Simply

Just because you write your subject simply doesn’t make the topic simple. The key is to understand a complicated idea and express it simply. Dawn gave some great tips to incorporate into your writing.

  • Use vocabulary that is easy to follow
  • Avoid jargon and cleaver wordplay
  • Get to the point quickly
  • Sort words and phrases. Consise 2 to 3 sentence paragraphs
  • Use half of the word count as for printed text
  • Replace passive phrases with active phrases
  • Don’t center text! Ragged left edge is difficult to read
  • Re-read and make sure it makes sense
  • One idea per paragraph
  • Keywords and the beginning and end of paragraphs

Many of the other text formatting tips are pretty straight forward and make it easier for the reader to consume your writing.

More Content Tips

Writing on the web, especially a blog, we have a few more tricks for styling and presenting our text content. These range from changing line breaks to prevent widows, controlling excerpt content, and moving users through your site.

When you have a post title or a subheading you might end up with one word on a second line if the title is long. The lone word is called a widow and is not desirable from a design standpoint. A way around this is adding in   to your title. This is a non-breaking-space and you can add a couple to push another word onto the next line. This is a workaround and isn’t the best coding wise, but helps the presentation.

On the main blog index you can show your entire posts, or you can define an excerpt. In your post you can either add a read more tag, or use a custom field to write your own excerpt.

Once you have people on your site, you want to keep them there. Linking within your article to other relevant content makes it easy for them to keep reading. You also get the benefit of Google rewarding you for self linking.

Images

With faster internet connection speeds there are more and more images on web sites. WordPress makes it easy to work with and align images in your articles and featured images are great to start your post off with a bang. Here are some good tips for working with images.

  • Use Large images. Especially your featured image as Facebook will grab this for the shared link.
  • Begin with the best quality image you can manage
  • Optimize images before you upload to WordPress
  • Reduce it to the appropriate size that you will use.
  • Be careful with image floats and alignment
  • Interesting images should get their own line
  • Make sure to rename your image file names
  • Try using captions to further explain the image. It’s another way for eyes to scan the page
  • Use images that are relevant, interesting, and appealing

1300 – Coding Together: A Dev Workflow

Peter Chester from Modern Tribe spoke about his journey from solo developer to working with a large team. There are benefits to working by yourself.

  • Control over the project
  • Low Overhead
  • Stay Competitive
  • Be Efficient

But with all these benefits come the mighty negatives. The stress, multitasking, many hat wearing and lonely times. Working with a team can lead to many more benefits that not only help you, but your customers.

One of the big things that Peter talked about was the development workflow. He shared his solo workflow, and how it evolved as more people began to work on the project.

At Modern Tribe they use the git-flow branching model. The above workflow begins by creating a new feature. It has many steps in quality control and testing before finally being merged into the project.

Another topic that Peter discussed was what he called Conscious Coding. In this he means we all need to code for not only ourselves, but for the coders and designers who will work with the code in the future. You need to use clearly named Classes, variables, function titles. These along with succinct documentation bring everything together.

1400 – Way of the Future

During Jon Trujilio’s opening talk about VVV he mentioned other projects were also using Vagrant for local development. Jason Cosper from WP Engine gave his talk on an exciting competetor to VVV, Mercury Vagrant (HGV). It was built by WP Engine to maximise your production environments to their hosting, but you can use HGV no matter where you end up hosting. And HGV is all about the future.

So many of todays sites run on old versions of PHP. HHVM from Facebook looked to be the future for WordPress, but then came PHP7. As Jason says, PHP7 is PHP on steroids, and he gave some impressive benchmarks.

Developers need to use these new tools to build sites for the future. VVV is great, and an industry standard. But it still ships with PHP 5.5. The beauty of HGV is the ability to not only test your site with PHP5.5, but also PHP7 and HHVM at the same time. You drop your files in one folder and then use subdomains to test the same site with different processors. There are even links in your WordPress Admin bar to switch between 5.5, 7, and HHVM.

Everthing about the future of coding relies on speed, and HGV is a great tool to test your site and prepare it for the future.

1530 – Ad Revenue 101

After several advanced course classes I switched back to the beginner room to hear Ben Ilfeld’s talk on WordPress Ad Revenue. I’ve never dealt with ads in a website so there was a lot to learn.

Ben began with a lot of information about the history of ad technology and the modern Ad Ecosystem. Ad Networks make it easy to aggregate media sites for advertising. New technologies changed the landscape with Real Time Bidding and Ad Exchanges. The Ad Networks transformed into these Exchanges where bidding and auctions were happening on a massive scale.

With the Ad Exchange you can sell space yourself with no need for a sales person. There is a lot of data and some sophisticated algorithms about each potential ad shown. Because of these large scales the prices are unbelievably low.

What are the other options?

You can choose to sell space yourself. Having a website with a good niche market would allow you to own the direct relationship with the advertisers. Another option is joining the global market and focus on growing your traffic.

You could also do both! But this is likely only for bigger sites.

How to get started

DoubleClick for Publishers by Google. It’s free but can be complex. Also good for managing direct sold, ad networks and exchanges. It’s owned by Google, so you know it’s not going anywhere.

There are other plugins for WordPress that let you manage your ads. Ad Code Manager is easy for non-developers to configure a complex set of ad codes. The plugin still works, but isn’t in active development.

Broadstreet is another service that is independent and affordable. It’s great for managing direct sold with smaller advertisers and it has an up to date WordPress plugin.

Another option for integrating ads is with a related posts plugin. YARPP or Yet Another Related Posts Plugin lets you integrate sponsored links next to your related posts.

No easy beginning

Something I got from the talk was there is no silver bullet to sucuessful advertising. You’re going to start small and have to work your way up. As you increase the demand for your audience you can add more ad networks and extensions to grow your revenue.

1645 – Lightning Talks

The day ended with three lightning talks, about 15 mintues each, and were jam packed with information.

iThemes Security

There was a lot to talk about so John Locke jumped into it and never slowed down. Here are some of the key points and benefits to using iThemes security

  • Update WordPress Salts, makes everyone re-login to Wordress. Great way to get the bad guys out quick.
  • Change database prefix
  • Change the wp-content folder name
  • Schedule backups of your database. Have these backups emailed to you.
  • XML-RPC request – Allow, Block, or just block Pinkbacks
  • 404 Detection – blocks out after a lot of 404 hits when someone is trying to find a backdoor
  • Change admin username and the database row. Not row number 1.
  • Away Mode – Set when your Dashboard is available. The login screen will be unavailable.
  • Brute Force Protection – join the network of blocking IP’s who are guilty of Brute Force
  • File change protection
  • Hide the login Area
  • Disable the file editor

I’ve been using a different security plugin for awhile but after all the great tools that John described I’ll be switching to iThemes soon.

ECommerce

Alex Christensen gave an introductory talk about selling through your WordPress site. He covered a ton of basic questions that you need to answer before you sell your first item. I didn’t take many additional notes but his slides are avaiable here.

Near the end of the slides is a big table detailing the abilities of six of the major ecommerce options. It’s a great tool for making sure the plugin you pick is the best choice for what you need

Forms

Russell Aaron ended the WordCamp with a talk all about forms. One of the first big pieces of knowledge he dropped was that WordPress is full of contact forms. You use forms to fill out information and send it to another place. Sometimes this is to fill out a new blog post and send it to the database, or saving settings to a different table in the database.

Another idea he discussed was about filters. WordPress keeps developing filters to keep your site safe. They also progress WordPress to become more. You use filters to help keep your front side forms safe from the public and their malicious content.

After telling a story of some ridiculous problems he’s caused with bad plugin updates he reminded us this fact of widsom: Plugins are not bad because they’re called plugins, they’re bad when a drunk coder pushes bad code.

Wrapping Up

I had a great time at the Sacramento Wordcamp and I wish I had starting going to Wordcamps years ago. There is so much to learn about Wordpress from some very talented speakers. I also made a few connections that I hope to keep in touch with and see again at the local Sacramento WordPress Meetup. If you haven’t been to a Wordcamp yet, what are you waiting for?

Relational Database in CodeIgniter

Crumpled Papers

My packing slips project for work has been well received and used by all our engineers. Now with daily use there are improvements and new features requested. This was the first app I built using CodeIgniter and I used some simple techniques along the way. In some cases I would have to completely rewrite sections to complete all the upgrades.

Vendors List

The first upgrade I made was the one of the simpler requests. In the first draft I hard coded two of the common addresses where we ship items. A drop down would list these address and when selected I used Javascript to fill in the address fields. I know my idea had been to just hard code more presets, but this was not going to work long term.

Enter the vendors table. I created a new table called vendors and added a separate page in the application to view and add new vendors. It’s a simple form that saves the name, address, city, state and zip code of a vendor. It also allows for editing and deleting from this Vendors page. My problem was finding a way to get this model and table data into the rest of the application.

It’s quite easy and only takes one query. I created a new function in my PackingSlips_model called get_the_vendors().

public function get_the_vendors()
    {
        $query = $this->db->get('vendors');
        return $query->result_array();
    }

Then in my controller I call this function when in the create function.

public function create()
	{
		$this->load->helper('form');
		$this->load->library('form_validation');

		$data['title'] = 'Create a Packing Slip';
		$data['vendors'] = $this->PackingSlips_model->get_the_vendors();

Now I have an array variable called vendors sent to the create page. Within my drop-down menu I loop through this array creating an option for each vendor.

<select class='select-address form-control' id='select-address'>
	<option value='none' selected='selected'>None</option>
	<?php
	    $i = 0;
	    foreach($vendors as $vendor) {
		echo "<option value='$i'>".$vendor['vendor_name']."</option>";
		$i = $i + 1;
	    }
	?>
</select>

Here I used my iteration variable to give each option the same index value of the array. This worked great to create a list of all the names of vendors. The only problem is this array is a PHP variable and I can’t use Javascript to interact with it.

I found the json_encode() function will return a JSON representation of the variable. Inside my script tag I can return my variable as a JSON object and set that to a Javascript variable.

var vendors = <?php echo json_encode($vendors) ?>;

Now that I have a Javascript variable with all of my vendors I can write the Javascript needed to watch the select and update the form with the data from the JSON object.

window.onload = function() {
        if(window.addEventListener) {
            document.getElementById('select-address').addEventListener('change', loadAddress, false);
        } else if (window.attachEvent){
            document.getElementById('select-address').attachEvent("onchange", loadXMLDoc);
        }
        function loadAddress(){ // When select change detected, use the vendors variable to fill in the address fields
        	var select = document.getElementById('select-address');
        	var val = select.options[select.selectedIndex].value;
        	var name = document.getElementById('slip_shipName');
        	var address = document.getElementById('slip_shipAddress');
        	var city = document.getElementById('slip_shipCity');
        	var state = document.getElementById('slip_shipState');
        	var zip = document.getElementById('slip_shipZip');
        	if(val == 'none'){ // Check if None preset selected
        		name.value = '';
        		address.value = '';
        		city.value = '';
        		state.value = '';
        		zip.value = '';
        		return;
        	}
          name.value = vendors[val]['vendor_name'];
          address.value = vendors[val]['vendor_address'];					
          city.value = vendors[val]['vendor_city'];
          state.value = vendors[val]['vendor_state'];
          zip.value = vendors[val]['vendor_zip'];
        }
    }

With this in place we can add any Vendor address using the Vendor’s form and be added to a new packing slip. I rolled out this update and started working on the next request, many devices per packing slip.

The actual relational database part

It took longer than I thought to describe the addition of a dynamic vendors list. Now let me move on to the bigger update. Currently you could only add one device to a packing slip. This was fine for the majority of slips created, but still needed improvement.

When I first built the app I used one database table that held all the data about the slip as well as the device. The first step was normalizing this table and move the device information to their own table. The relationship between the tables would be one to many. I started by creating a new table called ‘items’. I prefixed the fields with item_ except for the foreign key which I named slip_id_fk. This gave me a clear definition to create the relationship.

Before getting started I added sample data and got the single and index views working. My index page that listed all the slips used the name of the device as a title of the packing slip. I could now have many devices so I decided to add a field to the slip database called slip_description. This would be a short description used in both the main list of slips as well as the title of the single view.

My controller stayed the same

public function index()
	{
		$this->load->library('session');
		$this->load->helper('form');
		$data = array();
		$data['slips'] = $this->PackingSlips_model->get_slips();
		$data['title'] = 'Packing Slip Archive';

		$this->load->view('templates/header', $data);
		$this->load->view('slips/index.php', $data);
		$this->load->view('templates/footer');
	}

public function view()
	{
		$id = $this->uri->segment(2);
		$data['slips_item'] = $this->PackingSlips_model->get_slips($id);
		if (empty($id))
		{
			show_404();
		}
		$data['title'] = 'Packing Slip: #'.$data['slips_item']['slip_id'];
		$this->load->view('templates/header', $data);
		$this->load->view('slips/view', $data);
		$this->load->view('templates/footer');
	}

And in fact my model for the index page stayed the same as well. I decided the index list didn’t need to list any of the device information. Instead it shows the slip ID, Description, Vendor, FedEx Tracking #, Last Modified Date, and Status. This is all information from the Slips Table so I didn’t need to do any joins. Both the ID and the Description are anchor tags that link to the single view of the packing slip.

public function get_slips($id = 0)
	{
		if ($id === 0)
		{
			$this->db->select('*');
			$this->db->from('slips');
			$query = $this->db->get();

			return $query->result_array();
		}

So my query is a select all from slips. On a single slip view I needed to merge the info from the slips and items table. For this you use a join clause in your query. Here is the complete get_slips model

public function get_slips($id = 0)
	{
		if ($id === 0)
		{
			$this->db->select('*');
			$this->db->from('slips');
			$query = $this->db->get();

			return $query->result_array();
		}

		$this->db->select('*');
		$this->db->from('slips');
		$this->db->join('items', 'items.slip_id_fk = slips.slip_id');
		$this->db->where('slips.slip_id', $id);
		$query = $this->db->get();

		return $query->result();
	}

Here I’m using Codeigniter’s Query Builder class. I add properties to the query before it executes based on the if statement. The join clause lets us merge data from many database tables that we selecting from the database. The sql join needs several parameters.  First the table to add, then the fields that should match. The first field is the added table, and then the original. After that I add the where clause to limit the query to the id of the current page. The $id is passed from the controller. You’ll see I use the uri segment to get the ID and pass it on to the model.

My Controller uses the get_slips function and assigns it to the ‘slips_item’ index of $data. This variable is an array of objects that hold the data returned from the database. In my view template I echo data from the object using the first item in the array.

<?php echo $slips_item[0]->slip_shipName; ?>

This basic information is the same in each iteration of the array. I use the first one to print out the shipping and other information. Down the road I’ll need to see if there is a better way to go about this.

Next to display many devices I loop through the array and print out the item data.

<?php foreach ($slips_item as $item) : ?>
	<tr>
		<td><?php echo $item->item_manufacturer; ?></td>
		<td><?php echo $item->item_deviceName; ?></td>
		<td><?php echo $item->item_modelNumber; ?></td>
		<td><?php echo $item->item_serialNumber; ?></td>
		<td><?php echo $item->item_quantity; ?></td>
	</tr>
<?php endforeach;?>

Next step: Creating new relational database data

Viewing the relational data ended up being pretty easy once you get your head wrapped around database joins. I thought creating new database rows would be difficult, but it’s all about separating out what you need. Let’s begin with the controller.

public function create()
	{
		$this->load->helper('form');
		$this->load->library('form_validation');

		$data['title'] = 'Create a Packing Slip';
		$data['vendors'] = $this->PackingSlips_model->get_the_vendors();
		
		if ($this->form_validation->run('packing-slip') === FALSE)
		{
			$this->load->view('templates/header', $data);
			$this->load->view('slips/create');
			$this->load->view('templates/footer');
		}
		else
		{
			$this->PackingSlips_model->set_slip();

			$this->load->library('session');

			$this->session->set_flashdata('msg', '<div class="alert alert-success" role="alert">Packing Slip Created</div>');
			redirect('slips');
			return TRUE;

		}
	}

The first thing I do is load my helper files for form and form_validation. Next I bring in the vendors data that I mentioned at the top of this post. My initial version had a lot of form validation up next, but I learned about separating out the validation to clean up the controller. You can create a form_validation.php file in your config folder. Next you create a $config variable that is an array of different validations you’ll want to use in your application.

<?php 
$config = array(
	'packing-slip' => array(
		array(
			'field' => 'item_assetTag[]',
			'label' => 'Asset Tag',
			'rules' => 'required',
		),
		array(
			'field' => 'item_manufacturer[]',
			'label' => 'Manufacturer',
			'rules' => 'required',
		),
                etc...

Then when you want to run form validation as I do in my if statement above you just reference the name of the index in your config array. In this case “packing-slip.” I only have the one form to validate so I could have done it all in the controller, but I like the clean look here since I had so many items to validate. The views load if the form doesn’t validate (or reload with the error information), and the set_slips function runs if it succeeds.

public function set_slip($id = 0)
	{
		$this->load->helper('url');
		$this->load->helper('date');


		$slip_data = array(
			'slip_shipName' => $this->input->post('slip_shipName'),
			'slip_shipAddress' => $this->input->post('slip_shipAddress'),
			'slip_shipCity' => $this->input->post('slip_shipCity'),
			'slip_shipState' => $this->input->post('slip_shipState'),
			'slip_shipZip' => $this->input->post('slip_shipZip'),
			'slip_fedexTracking' => $this->input->post('slip_fedexTracking'),
			'slip_rmaNumber' => $this->input->post('slip_rmaNumber'),
			'slip_comments' => $this->input->post('slip_comments'),
			'slip_status' => $this->input->post('slip_status'),
			'slip_id' => $this->input->post('slip_id'),
			'slip_customerContact' => $this->input->post('slip_customerContact'),
			'slip_customerPhone' => $this->input->post('slip_customerPhone'),
			'slip_description' => $this->input->post('slip_description'),
			'slip_lastModified' => date('F j, Y g:i a')
		);

		$item_data = array(
			'item_assetTag' => $this->input->post('item_assetTag'),
			'item_manufacturer' => $this->input->post('item_manufacturer'),
			'item_deviceName' => $this->input->post('item_deviceName'),
			'item_modelNumber' => $this->input->post('item_modelNumber'),
			'item_serialNumber' => $this->input->post('item_serialNumber'),
			'item_quantity' => $this->input->post('item_quantity')
		);
	

		if ($id === 0 )
		{
			$this->db->insert('slips', $slip_data);
			$item_data['slip_id_fk'] = $this->db->insert_id();

			for( $i = 0 ; $i < count($item_data['item_assetTag']) ; $i++){
				$insert = array(
					'item_assetTag' => $item_data['item_assetTag'][$i],
					'item_manufacturer' => $item_data['item_manufacturer'][$i],
					'item_deviceName' => $item_data['item_deviceName'][$i],
					'item_modelNumber' => $item_data['item_modelNumber'][$i],
					'item_serialNumber' => $item_data['item_serialNumber'][$i],
					'item_quantity' => $item_data['item_quantity'][$i],
					'slip_id_fk' => $item_data['slip_id_fk']
				);
				$this->db->insert('items', $insert);
			}
		}
		else
		{
			$slip_data['slip_id'] = $this->input->post('slip_id');
			$this->db->where('slip_id', $slip_data['slip_id']);
			$this->db->update('slips', $slip_data);

			$item_data['item_id'] = $this->input->post('item_id');

			for( $i = 0; $i < count($item_data['item_assetTag']); $i++ ) {
				$insert = array(
					'item_id' => $item_data['item_id'][$i],
					'item_assetTag' => $item_data['item_assetTag'][$i],
					'item_manufacturer' => $item_data['item_manufacturer'][$i],
					'item_deviceName' => $item_data['item_deviceName'][$i],
					'item_modelNumber' => $item_data['item_modelNumber'][$i],
					'item_serialNumber' => $item_data['item_serialNumber'][$i],
					'item_quantity' => $item_data['item_quantity'][$i],
					'slip_id_fk' => $slip_data['slip_id']
				);
				$this->db->where('item_id', $insert['item_id']);
				$this->db->replace('items', $insert);
			}
		}

	}

Since this function handles both creating and updating data it has a lot going on. The first thing I do it grab my post data and assign the slip data and item data to their own array variables. In my form I assign the name of each of the devices to an array:

<input name="item_assetTag[0]" type='input' class='form-control' id='item_assetTag_0' placeholder='' value="<?php echo set_value('item_assetTag[]', ''); ?>">

So my structure of the $item_data variable for 3 devices is:

$slip_data
(
     'item_assetTag' => Array
          (
               [0] => a
               [1] => b
               [2] => c
          )
     'item_manufacturer' => Array
          (
               [0] => a
               [1] => b
               [2] => c
          )
     'item_deviceName' => Array
          (
               [0] => a
               [1] => b
               [2] => c
          )
     'item_modelNumber' => Array
          (
               [0] => a
               [1] => b
               [2] => c
          )
     'item_serialNumber' => Array
          (
               [0] => a
               [1] => b
               [2] => c
          )
     'item_quantity' => Array
          (
               [0] => a
               [1] => b
               [2] => c
          )
)

We’ll loop over this array in a second. First we deal with creating new table rows when the id is zero.

if ($id === 0 )
		{
			$this->db->insert('slips', $slip_data);
			$item_data['slip_id_fk'] = $this->db->insert_id();

			for( $i = 0 ; $i < count($item_data['item_assetTag']) ; $i++){
				$insert = array(
					'item_assetTag' => $item_data['item_assetTag'][$i],
					'item_manufacturer' => $item_data['item_manufacturer'][$i],
					'item_deviceName' => $item_data['item_deviceName'][$i],
					'item_modelNumber' => $item_data['item_modelNumber'][$i],
					'item_serialNumber' => $item_data['item_serialNumber'][$i],
					'item_quantity' => $item_data['item_quantity'][$i],
					'slip_id_fk' => $item_data['slip_id_fk']
				);
				$this->db->insert('items', $insert);
			}
		}

First we insert our slip_data array into the slips table. We need to know the id of that row to reference in our foreign key so we use $this->db->insert_id() to return the id of the last row created. I assign this to the ‘slip_id_fk’ key of my $item_data variable. Unlike the other values it isn’t an array so we’ll need to make sure we deal with that in our loop.

Next in the loop I count the number of items in the item_assetTag array. This will be the same count as the rest of the keys in the array so I just went with the first one. Then we create a new array called insert and assign the variables for our first new row. Make sure to use the [$i] key on each item_data field. Then we assign the foreign key, ‘slip_id_fk’, that we got from the database. We don’t need the iterator value here since it is not an array.

Then we insert that array of values into our table and loop through the next device. This way we can add as many new devices to a packing slip that we want.

Edit a relational database packing slip

When we open up the edit.php template I use a hidden input to capture the slip_id of the row we are editing.

<?php 
$attributes = array('class' => 'form-horizontal', 'id' => 'packing-slip-form');
$hidden = array('slip_id' => $slips_item[0]->slip_id);
echo form_open('slips/edit/' . $slips_item[0]->slip_id, $attributes, $hidden); 
?>

I also created a hidden input for the item id of each device.

<input type="hidden" name="item_id[]" value="<?php echo $item->item_id; ?>" style="display:none;">

This input is in a foreach loop that I’ll get to in a minute.

Now in the else portion of our set_slip function we grab the id’s before updating the database.

else
		{
			$slip_data['slip_id'] = $this->input->post('slip_id');
			$this->db->where('slip_id', $slip_data['slip_id']);
			$this->db->update('slips', $slip_data);

			$item_data['item_id'] = $this->input->post('item_id');

			for( $i = 0; $i < count($item_data['item_assetTag']); $i++ ) {
				$insert = array(
					'item_id' => $item_data['item_id'][$i],
					'item_assetTag' => $item_data['item_assetTag'][$i],
					'item_manufacturer' => $item_data['item_manufacturer'][$i],
					'item_deviceName' => $item_data['item_deviceName'][$i],
					'item_modelNumber' => $item_data['item_modelNumber'][$i],
					'item_serialNumber' => $item_data['item_serialNumber'][$i],
					'item_quantity' => $item_data['item_quantity'][$i],
					'slip_id_fk' => $slip_data['slip_id']
				);
				$this->db->where('item_id', $insert['item_id']);
				$this->db->replace('items', $insert);
			}
		}

And that’s about it for creating and updating relational databases. I did all this a few weeks ago so I forget exactly where I struggled the most. I know it took me a while to learn about the insert_id() function to get the actual id of the row created. For a while I was only writing to one database table and couldn’t figure out what the issue was.

Javascript for dynamic forms

Getting my data into the database was my first problem. Next I needed to figure out my form so that my engineers could add as many devices to the list as they needed, but also be able to target these devices to import data from our wiki.

Each form starts with one device so I hard coded a zero into the index for each necessary value. Then my “Add Device” button runs the following jQuery.

$('#add-device').click(function(e){
  	e.preventDefault;
  	counter = $('.device').length;
		$('#form').append(
			"<div class='row device' id='device_"+(counter+1)+"'>\
			<h2 id='device_1'>Device "+(counter+1)+"</h2>\
				<div class='col-md-6'>\
					<div class='form-group'>\
						<label for='item_assetTag' class='col-sm-3 control-label'>Asset Tag Number</label>\
						<div class='col-sm-9'>\
							<input name='item_assetTag["+counter+"]'' type='input' class='form-control' id='item_assetTag_"+counter+"' placeholder='' value=''>\
						</div>\
					</div>\
					<div class='form-group'>\
						<label for='item_manufacturer' class='col-sm-3 control-label'>Manufacturer</label>\
						<div class='col-sm-9'>\
							<input name='item_manufacturer["+counter+"]' type='input' class='form-control' id='item_manufacturer_"+counter+"' placeholder='' value=''>\
						</div>\
					</div>\
					<div class='form-group'>\
						<label for='item_deviceName' class='col-sm-3 control-label'>Device Name</label>\
						<div class='col-sm-9'>\
							<input name='item_deviceName["+counter+"]' type='input' class='form-control' id='item_deviceName_"+counter+"' placeholder='' value=''>\
						</div>\
					</div>\
				</div>\
				<div class='col-md-6'>\
					<div class='form-group'>\
						<label for='item_modelNumber' class='col-sm-3 control-label'>Model Number</label>\
						<div class='col-sm-9'>\
							<input name='item_modelNumber["+counter+"]' type='input' class='form-control' id='item_modelNumber_"+counter+"' placeholder='' value=''>\
						</div>\
					</div>\
					<div class='form-group'>\
						<label for='item_serialNumber' class='col-sm-3 control-label'>Serial Number</label>\
						<div class='col-sm-9'>\
							<input name='item_serialNumber["+counter+"]' type='input' class='form-control' id='item_serialNumber_"+counter+"' placeholder='' value=''>\
						</div>\
					</div>\
					<div class='form-group'>\
						<label for='item_quantity' class='col-sm-3 control-label'>Quantity</label>\
						<div class='col-sm-9'>\
							<input name='item_quantity["+counter+"]' type='input' class='form-control' id='item_quantity' placeholder='' value=''>\
						</div>\
					</div>\
				</div>\
			</div>"
		);
		$('#deviceNumber').append('<option value="'+counter+'">Device '+(counter+1)+'</option>');
		console.log('button clicked');
		counter++;
  });

When clicked it creates a counter variable that counts the number of current devices. I began with this hard coded, but when adding a device when editing a slip I needed a way to start with the current number and not 1. Then it creates new fields in the form for a device using the counter variable to increase the index number of each subsequent device. This was necessary to import data from our wiki using the following script:

var assetData = {};
	var deviceNumber = 0;

	function loadData() {
		console.log('loading-data');
		var $body = $('body');
		var $returned = $('#returned');
		var asset = $('#wiki-asset').val();

		var wikiRequestTimeout = setTimeout(function() {
			$('body').append("Failed to get wikipedia resources");
		}, 8000);

		var wikiUrl = "http://###.###.###.###/mediawiki/api.php?format=json&action=parse&page=" + asset;
		$.ajax({
			url: wikiUrl,
			dataType: "jsonp",
			success: function( response ) {
				var page = response.parse;
				var title = page.displaytitle;
				var text = page.text["*"];

				$returned.html(text);
				var $table = $('.wikitable tbody').first();
				$table.children('tr').each(function(e) {
					var key = $(this).find('th').text().trim();
					var value = $(this).find('td').text().trim();
					assetData[key] = value;
				});
				console.log(assetData);
				insertData(assetData);
				clearTimeout(wikiRequestTimeout);
			}
		});
		return false;
	}

	$('#wiki-submit-btn').on('click', function(e) {
		e.preventDefault();
		loadData();
		var asset = $('#wiki-asset').val();
		deviceNumber = $('#deviceNumber').find(":selected").val();
		$('#item_assetTag_'+deviceNumber).val(asset);
		$('#wiki-asset').val('927-######');
	});

	function insertData(assetData) {
		$('#item_manufacturer_'+deviceNumber).val(assetData['Manufacturer']);
		$('#item_deviceName_'+deviceNumber).val(assetData['Device Name']);
		$('#item_modelNumber_'+deviceNumber).val(assetData['Model Number']);
		$('#item_serialNumber_'+deviceNumber).val(assetData['Serial Number']);
	}

I wrote about how I was able to capture data from a mediawiki in this blog post. This script gets that data and then inserts it into the values of which ever selected device in the dropdown. That’s the deviceNumber, its a select with options for each device. Every time you click the Add Device button the javascript adds a new dropdown option to this select.

Wrapping things up

I still have some work to do on this project. I need to add the option to delete individual devices from a packing slip. I also need to rearrange some of the pages. The main change creating a new page as an archive for completed slips. I also need to add search functionality. But for now everything is working great and my coworkers are happy to use the application.

 

Mediawiki API – Connecting a WebApp to the Mediawiki Database

Computer screen full of code

I just completed a new project at the TV station creating a database for Packing Slips to send back equipment for repair. We wanted to not only be able to print out these slips, but also keep a record of them to easily see the history of repairs different devices needed. Our Mediawiki on site already had a lot of information about all of the devices in the station so I wanted to use that data as well as make an app that would scale well over time. In my research I found that not only did Mediawiki have an API that I could tap into, but it’s been shipped with it for years.

Mediawiki API

Connecting to your Mediawiki API is very straightforward.

http://path/to/wiki/api.php?

From here you add a format, actions and parameters to this end point to collect your data. I was only interested in making GET requests since I only needed to pull some data out of our device database so I didn’t have to worry about logging in or other more complicated API actions. You can read more about the Mediawiki API in their documentation.

Here is what my api request looked like for a random device in our database.

http://###.###.###.###/mediawiki/api.php?format=json&action=parse&page=927-000245

{"parse":{"title":"927-000245","revid":3269,"text":{"*":"<div class=\"assetPage\">\n<p><span class=\"assetTitle\" style=\"font-size:2em; font-weight:bold;\">QC 6 Vector Scope<\/span>\n<\/p>\n<table>\n\n<tr>\n<td>\n<table class=\"wikitable\" style=\"float:left;margin:0;\">\n<caption> Device Data\n<\/caption>\n<tr>\n<th> Manufacturer\n<\/th>\n<td> <a href=\"\/mediawiki\/index.php\/Tektronix\" title=\"Tektronix\">Tektronix<\/a>\n<\/td><\/tr>\n<tr>\n<th> Device Name\n<\/th>\n<td> QC 6 Vector Scope\n<\/td><\/tr>\n<tr>\n<th> Serial Number\n<\/th>\n<td> ######\n<\/td><\/tr>\n<tr>\n<th> Model Number\n<\/th>\n<td> ####\n<\/td><\/tr>\n<tr>\n<th> Software Version\n<\/th>\n<td>\n<\/td><\/tr>\n<tr>\n<th> Location\n<\/th>\n<td> <a href=\"\/mediawiki\/index.php\/Equipment_Rack_76\" title=\"Equipment Rack 76\">Equipment Rack 76<\/a>\n<\/td><\/tr>\n<tr>\n<th> IP Address\n<\/th>\n<td>\n<\/td><\/tr>\n<tr>\n<th> Router Source\n<\/th>\n<td>\n<\/td><\/tr><\/table>\n<\/td>\n<td>\n<table class=\"wikitable\" style=\"float:left;margin:0;\">\n<caption> Address for returns\n<\/caption>\n<tr>\n<th> Ship To Contact:\n<\/th>\n<td>\n<\/td><\/tr>\n<tr>\n<th> Attn:\n<\/th>\n<td>\n<\/td><\/tr>\n<tr>\n<th> Street Address\n<\/th>\n<td>\n<\/td><\/tr>\n<tr>\n<th> City State Zip\n<\/th>\n<td>\n<\/td><\/tr>\n<tr>\n<th> RMA Number\n<\/th>\n<td>\n<\/td><\/tr>\n<tr>\n<th> Customer Contact Name\n<\/th>\n<td>\n<\/td><\/tr>\n<tr>\n<th> Customer Contact Number\n<\/th>\n<td>\n<\/td><\/tr>\n<tr>\n<th> Reason for Return\n<\/th>\n<td>\n<\/td><\/tr><\/table>\n<\/td><\/tr><\/table>\n<\/div>\n<div class=\"packingSlip\">\n<div class=\"printHeader\">\n<p><a href=\"\/mediawiki\/index.php\/File:Working.PNG\" class=\"image\"><img alt=\"Working.PNG\" src=\"\/mediawiki\/images\/thumb\/c\/c0\/Working.PNG\/400px-Working.PNG\" width=\"400\" height=\"90\" \/><\/a>\n<span style=\"font-size:2em; font-weight:bold;\">Packing Slip<\/span>\n<\/p><p>May 24 2015\n<\/p>\n<\/div>\n<div class=\"printRow\">\n<div class=\"printAddressCell\">\n<table>\n\n<tr>\n<td style=\"width:120px;\">Address:\n<\/td>\n<td>#######\n<\/td><\/tr>\n<tr>\n<td>\n<\/td>\n<td>########\n<\/td><\/tr>\n<tr>\n<td>\n<\/td>\n<td>Phone: #######\n<\/td><\/tr>\n<tr>\n<td>\n<\/td>\n<td>Fax: #######\n<\/td><\/tr><\/table>\n<\/div>\n<div class=\"printAddressCell\">\n<table>\n\n<tr>\n<td style=\"width:120px;\">Ship To:\n<\/td>\n<td>\n<\/td><\/tr>\n<tr>\n<td>\n<\/td>\n<td>Attn:\n<\/td><\/tr>\n<tr>\n<td>\n<\/td>\n<td>\n<\/td><\/tr>\n<tr>\n<td>\n<\/td>\n<td>\n<\/td><\/tr><\/table>\n<\/div>\n<\/div>\n<div class=\"printRow\">\n<div class=\"printOrderCell\">\n<table>\n\n<tr>\n<td style=\"font-weight:bold;width:200px;\">RMA Number:\n<\/td>\n<td>\n<\/td><\/tr>\n<tr>\n<td style=\"font-weight:bold\">Customer Contact:\n<\/td>\n<td>\n<\/td><\/tr>\n<tr>\n<td style=\"font-weight:bold\">Customer Phone #:\n<\/td>\n<td>\n<\/td><\/tr><\/table>\n<\/div>\n<\/div>\n<div class=\"printRow\">\n<table class=\"wikitable\" style=\"width:100%\">\n<tr>\n<th> Product\n<\/th>\n<th> Description\n<\/th>\n<th> Model\n<\/th>\n<th> Serial Number\n<\/th>\n<th> Ship Quantity\n<\/th><\/tr>\n<tr>\n<td> <a href=\"\/mediawiki\/index.php\/Tektronix\" title=\"Tektronix\">Tektronix<\/a>\n<\/td>\n<td> QC 6 Vector Scope\n<\/td>\n<td> 1720\n<\/td>\n<td> #######\n<\/td>\n<td> 1\n<\/td><\/tr>\n<tr>\n<td style=\"height:1em;\"> <\/td>\n<td> <\/td>\n<td> <\/td>\n<td> <\/td>\n<td>\n<\/td><\/tr>\n<tr>\n<td style=\"height:1em;\"> <\/td>\n<td> <\/td>\n<td> <\/td>\n<td> <\/td>\n<td>\n<\/td><\/tr>\n<tr>\n<td style=\"height:1em;\"> <\/td>\n<td> <\/td>\n<td> <\/td>\n<td> <\/td>\n<td>\n<\/td><\/tr>\n<tr>\n<td style=\"height:1em;\"> <\/td>\n<td> <\/td>\n<td> <\/td>\n<td> <\/td>\n<td>\n<\/td><\/tr><\/table>\n<\/div>\n<div class=\"printRow\">\n<table>\n<tr>\n<th> Reason For Return\n<\/th><\/tr>\n<tr>\n<td>\n<\/td><\/tr><\/table>\n<\/div>\n<\/div><a href=\"\/mediawiki\/index.php\/File:1720.jpg\" class=\"image\"><img alt=\"1720.jpg\" src=\"\/mediawiki\/images\/3\/34\/1720.jpg\" width=\"600\" height=\"449\" \/><\/a>\n\n<!-- \nNewPP limit report\nPreprocessor node count: 64\/1000000\nPost-expand include size: 2272\/2097152 bytes\nTemplate argument size: 91\/2097152 bytes\nExpensive parser function count: 0\/100\n-->\n"},"langlinks":[],"categories":[{"sortkey":"","*":"Asset_Tags"}],"links":[{"ns":0,"*":"Equipment Rack 76","exists":""},{"ns":0,"*":"Tektronix","exists":""}],"templates":[{"ns":10,"*":"Template:Asset Tag","exists":""}],"images":["Working.PNG","1720.jpg"],"externallinks":[],"sections":[],"displaytitle":"927-000245"}}

As you can see its not as easy to pull specific information you want when the api returns a page like this. All of the content in the page is wrapped in the text object with a key of *. 

I needed to get into all of that text and just pull out the data. I used Semantic Mediawiki Forms to create this database so I didn’t have access to give the table cells I needed a class or an id that I could access through javascript. I came up with a solution that might not be the cleanest, but it worked.

My Javascript Solution

I decided I would use Javascript to connect to the API, then spit out the returned html into a hidden div on my page. Then with jQuery I would parse through the html and grab the information I needed. Since every device page would be the same I only needed to work out the jQuery the one time. Here is my final working solution:

var assetData = {};

	function loadData() {
		var $body = $('body');
		var $returned = $('#returned');
		var asset = $('#wiki-asset').val();

		var wikiRequestTimeout = setTimeout(function() {
			$('body').append("Failed to get wikipedia resources");
		}, 8000);

		var wikiUrl = "http://###.###.###.###/mediawiki/api.php?format=json&action=parse&page=" + asset;
		$.ajax({
			url: wikiUrl,
			dataType: "jsonp",
			success: function( response ) {
				var page = response.parse;
				var title = page.displaytitle;
				var text = page.text["*"];

				$returned.html(text);
				var $table = $('.wikitable tbody').first();
				$table.children('tr').each(function(e) {
					var key = $(this).find('th').text().trim();
					var value = $(this).find('td').text().trim();
					assetData[key] = value;
				});
				insertData(assetData);
				clearTimeout(wikiRequestTimeout);
			}
		});
		return false;
	}
    $('#wiki-submit-btn').on('click', function(e) {
		e.preventDefault();
		loadData();
		var asset = $('#wiki-asset').val();
		$('#asset-id-form').hide();
		$('#slip_assetTag').val(asset);
	});

	function insertData(assetData) {
		$('#slip_manufacturer').val(assetData['Manufacturer']);
		$('#slip_deviceName').val(assetData['Device Name']);
		$('#slip_modelNumber').val(assetData['Model Number']);
		$('#slip_serialNumber').val(assetData['Serial Number']);
	}

First I assign a couple jQuery objects for the body as well as the returned div that is hidden from view. I also created a global variable that I would append my data to.

Next I grab the page name that was entered into the form and append that onto the wikiUrl variable and use this to make the ajax request.

After a successful connection to the mediawiki server I create a variable page that is the full response from the connection. That’s the json object that is above. Next I assign a new variable to the text objects * key and then insert that block of html into my returned div. Next I create a jQuery object of the first table that was in that block of html. That first table is the only one that I care about so I’m working my way down to the data that I need. Next I go through each of the children table rows of that table and assign the th to the key, and the td to the value of my assetData variable. After that I run a function that assigns those values from my assetData variable to the values of my form.

As I said it might not be the cleanest way of doing things since I am injecting a bunch of html in a hidden div but I found it works and returns the data very quick. After I setup the program on our internal web server it only takes a second to get the data and insert them into the form.

This is only one part of the application I built for creating a packing list database. I created it with Codeigniter v3 but I’ll save that write up for another post.

Graphviz: A Better Way to Create Flow Charts

Working on laptop computer

A while back I wrote about the wiki that I set up for the television station that I work at. Using the mediawiki software I setup the wiki on an intranet webserver to handle our troubleshooting and technical guides as well as a directory of our equipment. We’ve made good progress over the two years we’ve been contributing to the wiki and I made a recent discovery that makes adding troubleshooting flow charts a breeze.

Graphviz is an open source graph visualization software that allows you to structure your data and display it in a number of ways. Their gallery shows the vast number of options that you can utilize to better show off your data.

I needed a way to add our troubleshooting flow charts when we have problems with our television transmitter. I also wanted to be able to have people click on a section of the flow chart to be taken to the wiki page with any extra details they would need for that step. Adding these links is a little harder with Graphviz but I was able to work around it.

The trick to adding links is to use a record shape in your graph. This lets you use HTML in the label for that node. It gets clunky, but here is the example of one node that is a link.

box1 [shape=record, label =<
<table border="0" cellpadding="0" cellspacing="0" TITLE="Main Transmitter">
  <tr>
    <td href="http://###.###.###.###/mediawiki/index.php/MRC_Site_2">Is the Main Transmitter On</td>
  </tr>
</table>>];

I found it interesting that you can’t create an anchor tag, instead you add an href property to your <td>. Graphviz has a ton of documentation for configuration and organizing structures. I’ve primarily been working with the dot framework but they also have options for a “spring model” layout, multiscale spring model, radial layouts, and circular layouts.

Adding GraphViz to our mediawiki

To use with the wiki I’m using the Graphviz mediawiki extension. To use the extension you add your code into a pair of <graphviz> tags and save the page. Unfortunately you have to save the page to see any changes, the preview option will not render a new image. Also if you have any errors in your code the image will not render and you’ll be left with a blank page. There is no feedback of what the problem is so you’ll have to scour the code to find it. The code inside the <graphviz> tag is run through the GraphViz program which compiles the code and outputs an PNG image (or other format that you choose). With the mediawiki extension the file is automatically uploaded to your wiki with a file name of the page name followed by digraph name-of-node and then the format of the graph, in my case dot. When you make a change the file name stays the same so you get a nice file history of all your changes.

After you name your graph you create all of the nodes and give them attributes, and then you define the connections between the nodes. Creating a node is a simple as giving it a name and ending the line with a semicolon. If you define a node before this the new one you create will have all of the same attributes as the node definition.

node [shape=circle; fillcolor="green";style="filled"];
greencircle_1; greencircle_2;
redcircle_1 [fillcolor="red"];

In this example I defined a node as a circle filled with green. I created two nodes which can be each on their own line, but I prefer to list them all next to each other for simplicity. Then I made a redcircle node, and only changed the fill color attribute. This node will take all of the previous attributes and then overrite the one that I specified.

This small example is similar to CSS classes, where a basic class has many attributes and a modifier class only changes a specific one or two to create a new style.

If I don’t add a label to an individual node or a node definition than the node will use its name as the text inside it. You can use escape characters in the label to create new lines as you’ll see in my example.

An example graph

Here is an example of the graph I created for our main troubleshooting flow chart when we lose our off air signal.

<graphviz>

digraph R {
node [shape=record; fontname=Ariel];
infobox [shape=square; label="This\neliminates\nSTL\nMicrowave\nProblem and\nEncoder\nSystem\nProblem"];
box1 [label =<
<table border="0" cellpadding="0" cellspacing="0" TITLE="Main Transmitter">
  <tr>
    <td href="http://###.###.###.###/mediawiki/index.php/MRC_Site_2">Is the Main Transmitter On</td></tr>
</table>>]; 
box2 [label="Switch Exciters"]; 
box3 [label="Problem Fixed?"]; 
box4 [label="Try to Turn Main Transmitter Back On"]; 
box5 [label="Problem Fixed?"]; 
box6 [label="Turn on Aux Transmitter"]; 
box7 [label="CALL ENGINEERING"];
node [shape=circle, fixedsize=true; width=0.9;label="yes";fillcolor="green";style="filled"];
yes1; yes2; yes3; yes4; yes5; yes6;
node [label="no";fillcolor="red"; style="filled"];
no1; no2; no3; no4;

box1->yes1;
box1->no1;
yes1->box2;
box2->yes2;
yes2->box3;
box3->yes3;
box3->no2;
no1->box4;
box4->yes4;
box4->no3;
yes4->box5;
box5->yes5;
no3->box6;
box6->yes6;
box6->no4;

yes3->box7;
yes5->box7;
yes6->box7;
no2->box7;
no4->box7;

labelloc="t";
label="No Over-The-Air Signal\nGUI Control Available";
fontsize="20";
}
</graphviz>

And this is the image that is generated.

Troubleshooting Flow Chart from GraphViz

I’ll probably make improvements as we move on but this is a good start and an easy to follow flow chart for my staff at the station. Each box, aside from the Problem Fixed? ones, will be a link to a wiki page with the steps to perform the task listed. Either turning on the Auxiliary Transmitter or using the GUI to turn the transmitter back on.

I’ve only begun to scratch the surface of what GraphViz is capable of. I’m not sure if we’ll need all the bells and whistles for our wiki, but I’ll continue to learn as many features and make use of them as best I can.

My path to learning Javascript

A Person overlooking a winding road

I’ve jumped around to a bunch of programming languages and I decided both through my own frustrations and the suggestions of my peers that I need to hone in on one language. It should be one that you intend to use in my future projects and a core language that sees lots of use in the real world. I decided to focus on learning Javascript, a language I’ve been flirting with for quite a while.

I found Javascript is Sexy had put together a very thorough plan of action to make the best use of your time. Many people in various Reddit programming subreddits had formed study groups to work through the course together. I kept missing a new starting group so I decided to just work through it on my own. Since I’ve been working with programming for a couple years now I began working through the “Study Guide for Experienced Developers” and picked up David Flanagan’s JavaScript: The Definitive Guide.

I worked through the first few weeks of the learning guide and just finished the first project, a dynamic quiz! The requirement was to start with a Javascript object that contained all of the questions of the quiz, and then show one question at a time and then show just the users score after the final question. We had to build the quiz in a way that would allow for any number of questions, and any number of answers for each question.

I decided to use vanilla Javascript and not use any jQuery. I will probably rebuild the quiz using jQuery before I move on to the next step in the project.

Here is my quiz in action:

See the Pen History Test by Anthony Skelton (@ajskelton) on CodePen.

It’s probably a little rough around the edges but it fulfills all of the requirements of the project. I peaked ahead and the next couple rounds of the project will be continuing to improve on this project.

Probably the hardest part for me to get through on this part of the project was getting the value of the answer provided and checking that against the correct answer. I was about to find some help and setup a function just to check the values, and then used that function as part of my checkScore function

function getRadioVal(form, name) {
  var val;
  var radios = form.elements[name];
  
  for (var i = 0, len = radios.length; i<len; i++) {
    if ( radios[i].checked ) {
      val = radios[i].value;
      break;
    }
  }
  return val;
}

function checkScore() {
  var val = getRadioVal(document.getElementById('test'), 'answer');
  if (val == allQuestions[counter].correctAnswer) {
    score++;
  } else {
    incorrect.push([counter, allQuestions[counter].choices[val]]);
    console.log(incorrect);
  }
}

I’ll do an update when I finish the next section of the project. Now back to more reading!

My Steam Achievements Plugin is Officially Launched

Wordpress Steam Achievements Plugin

After realizing that my achievements plugin hosting request at WordPress.org was not the final step in the process I successfully went through the steps to push my plugin to the repository.

https://wordpress.org/plugins/steam-achievements/

I kept checking back and searching for the plugin but it was taking forever to be added. I then did a little more research and saw that even though I had the plugin in a zip file they weren’t going to do the work for me and I had to upload it myself. I probably should have realized it sooner but got caught up in other things.

The process was actually quite easy. I followed a walkthrough from the Digging Into WordPress Blog and there are very few steps.

  • Create a folder inside your plugins main directory to house the local version of the repository
  • Checkout the svn from your approved directory
  • Copy the files into the local version folder.
    • Screenshots into the Assets folder
    • All other files into the Trunk folder
  • Check in the svn

I like that checking in the svn automatically connected and uploaded my changes to the repository. I was anticipating something similar to git where you add the files, then commit them, and then push. This seemed to skip a step. I was so happy the process was easy I instagrammed my success.

Pushing my first plugin to the WordPress repository.

A photo posted by Anthony Skelton (@mranthonyskelton) on

Now that the plugin is in the repository I’ve started plans for the next update. So far it only adds your TF2 achievements. Next up will be CSGO and Left For Dead 2. I’ll have to research from there what games are most popular and in need of something like this. DOTA2 probably needs its own plugin since the game is so big.

Here’s my project page that will have all of the updates and information

Intro to the WordPress JSON REST API

WordPress API

Last night I attended my local WordPress Meetup with the topic of the WordPress JSON REST API. I was really excited to attend because the whole idea of a REST API is something I know about, I just don’t really know what it does and what the purpose of it is. All that has changed.

Getting Some Closure

The discussion was led by Vasken Hauri of 10up. The subtitle for his talk was “Using the WP JSON API & Best Practices for Javascript and jQuery in WordPress.” He gave a great overview of how the API can be used and then launched into some code for best practices. There were a few moments I was very puzzled, then I realized that I knew what he was talking about, I was just used to seeing it in a different way.

My main experience in using a JSON API was my recent work on the Steam Achievements plugin I’ve been working on. Now I see that with the API plugin installed in your WordPress you can connect to the site to perform CRUD operations. JSON is great to work with because its a lot of data in a small package, and it’s a standard for giving and getting data across the internet. Using JSON to communicate to your WordPress site gives you a way to separate the data from the presentation.

This is best understood by a couple examples that were presented. This JSON REST API plugin was developed by the MOMA blog Inside / Out. Their site is presented as a Ruby on Rails front end, but use WordPress as their publishing platform. The use the JSON API in their Ruby Templates that pull the data from the WordPress Database.

Another great point that Vasken mentioned is the JSON end points will still work with cached pages. It will also be backwards compatible when WordPress adds the JSON API to WP Core, which will be happening in the next couple of updates.

There is a Chrome extension called Postman that lets you play around with all of the JSON REST API your site is outputting. You can even do it while running a site on a local server. I just installed it in Chrome and looking forward to seeing what I it can do.

Best Practices Going Forward

With the addition of the JSON REST API to Core its going to mean a lot more people are writing Javascript and Vasken wanted to give an overview of why its important to code in a way that wont screw things up in the future.

He began with some good examples of performance. Reminding us that it in PHP you want to avoid multiple calls to your database. Similarly in JS you want to avoid multiple calls to your DOM. Instead you should save the object that you call into a variable. However with all of these variables being made it can be a problem if you don’t plan your naming and run into name collision.

Prefixing your function names is a good option, but you can do one better in both PHP and in JS. Object Oriented PHP lets us avoid function name collisions with creating a class and instantiating it.

Whenever you have to globalize a variable make sure that it is unique. Don’t get lazy and give yourself problems in the future.

Javascript has a similar concept called Closures. Everything you can get with a PHP class you get with a Javascript closure.

With more Javascript being written to work with the JSON REST API we should be working within closures so we create functions that act on an instance but don’t go anywhere and muck things up.

Key Concepts

In closing Vasken gave us a few concepts to make sure we left with.

  • Write performant Javascript – Think about the limitations of your users and their devices. He recommended jsperf.com to test your Javascript and compare in different browsers/computers.
  • Consider the WordPress Ecosystem
  • Use Closures for your plugins whenever possible

I still have a lot to learn when it comes to Javascript. I’ve been reading David Flanagan’s Javascript: The Definitive Guide. It’s slow progress since I have so much else going on but I want to continue to expand to better jQuery and to a framework like Backbone or Angular as well.

There’s a lot on the horizon, but I’m ready to take it on.

WordPress Plugin – Team Fortress 2 Achievements

One of the fun things with most Steam games are the achievements that you can earn while playing. Some are silly, some ridiculously difficult and all are very satisfying when you hear the achievement sound fx in the middle of a match. Some people will “farm” these achievements on an idle sever but I always prefer to earn them in matches, even if it’s just a pub. I know I get annoyed when someone else earns an achievement on my death so I hope other get that same annoyance.

The design team for the Team Fortress 2 Achievements also put a lot of work into these icons and they look great.

Team Fortress 2 Achievements Beaux and Arrows Team Fortress 2 Achievements Duty Bound Team Fortress 2 Achievements Real Steal Team Fortress 2 Achievements OMGWTFBBQ Team Fortress 2 Achievements Search Engine Team Fortress 2 Achievements Pilot Light Team Fortress 2 Achievements The Cycle Team Fortress 2 Achievements Pushkin the Kart Team Fortress 2 Achievements Attack o' Lantern Team Fortress 2 Achievements FYI I am A Medic

Whenever your playing TF2 you can see your most recent achievement, or you can go to your community portal page and see the completed list along with other stats. I wanted a way to display my recent Team Fortress 2 Achievements on my own site so I started to build a plugin to do just that.

Steam API

Steam does a good job of working with developers and providing them with an API to connect to data from games owned to stats and achievements. These were first done with XML API, but a newer 2.0 version for Web API is recommended. It also requires an API Key, which you can create here. The API key requires you to log in to Steam so it can track the different requests that you make. I had planned to use the this new api to collect the user data for the plugin but ran into a problem: the newer API didn’t include the unlock Timestamp.

Without this property there is no way to order the achievements and show the most recent ones achieved. So I had to go back and use the older XML API. There are actually two ways to get the XML, either with the profile name like Lunch_Meat, or the 64 bit profile ID.

http://steamcommunity.com/id/PROFILENAME/stats/APPID/achievements/?xml=1
http://steamcommunity.com/profiles/PROFILEID/stats/APPID/achievements/?xml=1

I built the plugin so you can user either the name or the 64bit ID in case the user never defined a custom URL on their community profile. After you save your name the plugin connects to the Steam xml and saves the xml data to your options folder to reduce the number of calls to Steam. All of the achievement icons are hosted on Steam’s CDN which are correctly linked to in the xml data.

Sorting the data

After the XML file is loaded and before it is saved to the options field I run it through a function to sort the achievements in the reverse order of completion.


function most_recent_achievements($wpsteam_tf2_xml) {
	$obj_achievement = array();
	$i = 1;
	if($wpsteam_tf2_xml->{'achievements'}->{'achievement'} != null) {
		foreach($wpsteam_tf2_xml->{'achievements'}->{'achievement'} as $item) {
			if($item[0]["closed"] == 1) {
				foreach($item as $key => $value) {
					$achievement[(string)$key] = (string)$value;
				}
				$obj_achievement[] = $achievement;
			}
		}
		usort($obj_achievement, "sort_array_timestamps");
		return $obj_achievement;
	}
}

function sort_array_timestamps($a, $b) {
	return($b['unlockTimestamp'] - $a['unlockTimestamp']);
}

All that data was buried pretty deep hence the multiple foreach loops but I think I did it as efficiently as possible.

Link to the Plugin

This is my first post about the Achievement Plugin, you can find the most up to date information on the Steam Achievements Project Page. This is the first plugin I’ve developed so I’m still working on getting it added to the repository.

What’s up next?

This plugin is designed to only work with the achievements from Team Fortress 2. However, there are achievements in pretty much every game in the Steam gaming ecosystem so I hope to expand it to work with other games as well. The first two will be CS:GO and DOTA2, as these three make up the majority of playtime on Steam.

Just Build Websites

computer practice wordpress

I often fall into a pattern when I’m learning new things. I get really excited and want to learn everything. Then I learn about a related topic, and shift all focus to the new thing. This makes me somewhat knowledgeable in a lot of things, but never really great at one thing. I’ve always heard the term “A jack of all trades is a master in none” and I always thought that I could overcome that stigma.

It’s not that easy.

Just telling myself that I can still be very proficient in lots of things and still be very successful only gets you so far. I’m not complaining about the life I’ve lived, because I’ve had a lot of good times. I think I’m looked at as someone who knows what they’re doing. And most of the time I do. But I have bigger goals and accomplishments I want to make for myself and this cyclical status quo wont get me there.

The past month I began to learn Ruby. I’ve been working with WordPress sites for a while and getting pretty good with my PHP but I had a crazy idea for an app that I wanted to develop and thought that Ruby on Rails would be the best platform for that. I did some research and didn’t see anyone who had done my idea yet so I thought I was in a good place. I found a couple Ruby books and began the Ruby on Rails track on Treehouse.

Probably a big factor in my wanting to learn everything comes from my sources of education. I’ve jumped around a lot of the big learning sites like Tuts+, Code School, and most recently Treehouse. I think you can get a lot of basic knowledge from these sites and they push you in the right direction, but you need to step back after you learned new skills and practice them. Since I was paying a monthly subscription I always wanted to make the best use of my money and keep learning more and more skills. I would jump from one course to the next. This made my quick jump into Ruby land possible. But instead I should have taken a step back and continued to develop and practice WordPress skills that I had just learned.

I had just finished the WordPress plugin Treehouse course before jumping ship so I had ideas for a few different plugins that I just abandoned. This morning when I went to look at them I recognized some things but I had forgotten a lot since I never made time to practice. This time I want to break my cycle.

I have a couple ideas for WordPress Plugins that I’m going to work on. I’m also going to work on developing themes from PSD files. I’ve found a few free PSD site layouts that I’m going to use to  design themes. They may not be the best sites, but they’ll give me good practice in building a quality theme from the ground up. After I’ve done several that I feel confidant about I want to develop a solid theme that I can release to the free theme repository and begin to give back to the community.

 

A Designers Guide To WordPress

designers guide

I’ve been attending the Sacramento WordPress Meetup Group for the past few months and I’ve enjoyed discussions talking about Genesis, Responsive Styling, and most recently how to design for WordPress. For this most recent talk we had a guest speaker from the Bay Area, James Hipkin, from Red8 Interactive.

Mr Hipkin mentioned a couple times during the discussion that he is not a designer, nor a developer. Instead he brought a unique perspective as the manager of a creative team. He interacts with the clients and has a first hand look at things that do and don’t work. The topics ranged from how to best start a project to designing responsively and responsibly. I wanted to touch on a few things that really stood out to me as a developer in his designers guide to wordpress.

Responsive vs. Adaptive

One of the first things covered were some basics of web design before jumping into WordPress specific topics. Mr Hipkin first talked about designing mobile first and mentioned one of their clients, Bev Mo, recently surpassed 50% mobile traffic on their site. He then talked about how he differentiates between a responsive and an adaptive site. I’ve never had a great answer for the difference but his explanation made a lot of sense.

Responsive sites adjust all the content of the site to fit the screen being displayed. Whereas Adaptive change the content that is available based on the device. A great example was a call now button that might show up on a mobile phone, but disappears once the screen size is beyond mobile devices. Another example was a slider that might turn into just a static image on mobile.

While the difference is slight I feel more confident in this discussion with future clients.

Static Content

Using WordPress I often want to make it so the client could go in and change any part of the site. I mean, that’s what makes WordPress so easy, the customizable back end that doesn’t scare off clients. However if speed is of upmost concern (and when isn’t it?) you want to limit the number of calls to the database. This means if you have content that doesn’t need to change, like their social links, phone number, or other static content you can build it into the html to minimize the amount of times the database is accessed. So the footer doesn’t necessary need every part to be widgets. You can build things into the template directly.

Control your Visual Editor

Mr Hipkin brought up a great point when talking about all the elements that need to be styled. He said clients often forget to specify what they want the styles of their visual editor to look like. There are a lot of controls on top of the content box and lots of ways the client can kill the site if things are not styled appropriately.

Footer Fettish

Ok well he didn’t mean to talk about the footer in this way. Mr Hipkin just said he wished more love was given to the footer as they are often forgotten by the client and designer and can hold a lot of secondary information. He said he wished there was a group for people who liked the footer as much and this was turned into a footer fettish by the audience. But potty humor aside it’s a great point to make your design with the footer in mind. It’s a great place to put terms and conditions, style guides, contact information, newsletter signups etc.

Closing Thoughts

James Hipkin is a great speaker and obviously very excited to talk about all things WordPress. He answered a lot of the audiences questions as he went through his talk and also took some time to show us examples of work they had completed. He also gave a lot of insight on how to work with clients and build your design business. I know Red Cart will be no where near what Red8 is any time soon but it’s a nice thing to shoot for.

You’ll never get anywhere if you never try.