Automate Everything w/ Bash, Linux & Command Line
  1. Pinterest Pin It Button/Bookmarklet Hybrid

    AKA - Pinterest “Pin It” Button Implementation Revisit

    I wrote a post about a year ago about how to install the Pinterest Pin It button. Why would I have to do that? Well, because the code generated in the developer docs was incomplete, confusing and led to many many broken implementations on sites. I know that’s true because of how popular that post was.

    Read the old post here.

    Pin It - A Year Later

    Well, I’m writing this post because many of the same issues still exist. They have done a better job of making sure that people understand how to install the code, but they’ve still allowed it to be easy for people to install it incorrectly on their sites. The biggest problem is when the media parameter isn’t tagged properly in the button href.

    The original version would just fail if an image wasn’t specified. The new version allows you to pin the page, with a broken image. How much sense does that make?

    The Pin It Bookmarklet Works…

    What makes all this worse is that the Pinterest bookmarklet that they’ve had since the very beginning has more functionality in it than the button does. Ever notice that? It’s really mind-boggling.

    Why wouldn’t they just mimic the functionality of the bookmarklet with the Pin It button? When you use the bookmarklet it gives you a gallery of images for you to choose from to use in your pin. That makes the bookmarklet usable on many different types of pages with no configuration required. Whereas the button has to have one image hard coded to it. This makes zero sense.

    So I thought… Why not just rewrite the button functionality so that it calls the Javascript from the bookmarklet instead of the code the button would normally run? Would that work? YES IT DOES!

    The Pin It Button - Pin It Bookmarklet Hybrid

    The implementation is really simple. Just start out by adding the following code, as recommended by Pinterest, on the page where you want the button to appear. The one change is that I’ve added an ID to a surrounding <span> tag.

    <span id="pin-it"><a href="//pinterest.com/pin/create/button/"><img src="//assets.pinterest.com/images/pidgets/pin_it_button.png" alt="image" /></a></span>
    

    Then, just add the following script to your page. Make sure you have the jQuery library on the page as well.

    <script type="text/javascript">
        jQuery.getScript('//assets.pinterest.com/js/pinit.js', function() {
            jQuery('#pin-it a').attr('href', '#');
            jQuery('#pin-it a').attr('onclick', "javascript:void((function(d){e=d.createElement('script');e.setAttribute('type','text/javascript');e.setAttribute('charset','UTF-8');e.setAttribute('src','//assets.pinterest.com/js/pinmarklet.js?r='+Math.random()*99999999);d.body.appendChild(e);}(document)));");
        });
    </script>
    

    That’s it. You should now get the bookmarklet action when the button is clicked, which will show a gallery of images on the page to choose from to use in your pin.

    Here’s an example implemented right here: image

    Anyway… Happy pinning!

     
  2. Big Data, Privacy & Ad Targeting

    I think it’s important to talk about my perspective and potential bias. I’m a digital marketer. It’s what I do. But, sometimes I feel like Harvey Dent.

    {Image Source}

    I use cookie based tracking data every day for website optimization, ad targeting and business intelligence. There’s no way to deny how powerful an understanding of the information available, even with a vanilla install of Google Analytics, can be to your business. There are often very enlightening stories about what website users want, need or don’t understand that will help you improve your product. The structure, quantity, organization and analysis of this data is getting better at a fanatic pace. I feel like the big gap between how this data is used and how the general population speculates about it’s use is just too wide.

    Or, Popular Are Privacy Concerns Right On Target?

    I continually ask myself that question. As a consumer, I quit using Facebook. It wasn’t all about privacy but it had a role in my decision. But Facebook isn’t the only offender. Not by a long shot.

    Recently there have been a few time where I’ve really had to stop, think and question my perspective on ethics surrounding online tracking technology. A couple of those prompted this post.

    De-Anonymizing Tracking Data

    What does that mean? Well, all the tracking data provided in common analytics packages like Google Analytics is anonymous until the visitor fills out a form and tells you who they are. This level of privacy is by design.

    There are companies springing up that seek to change that. They pool data together from sites across their network partners that track the behavior of a visitor. When that visitor identifies him/herself on site A, then all the partner sites will know who that anonymous visitor was without the visitor actually telling site B, C or D.

    Here’s the post I read that explains this much more effectively than I can. It’s creepy and I think it’s unethical.

    It isn’t just new emerging businesses or technologies that can be creepy/evil. In fact, the bigger data players like Google have the ability to make these connections now. But are they?

    When Ads Are Too Personal

    Until now, the news of my wife and I separating hasn’t been public. The decision was made about 1 month ago. My communication of that with friends, family and co-workers has been limited to word of mouth, GTalk and SMS.

    Imagine my surprise when I saw this ad at the top of my GMail account last night…

    If you cannot imagine - I was creeped the fuck out.

    After the shock of it wore off I started to think about how it was possible for this ad to be so spot on. To be honest, I have no way of knowing. And because I don’t know I’m creeped out. I don’t like it. Instead of ads being relevant, useful and persuasive, this ad gave me chills (not the good kind).

    So, how? One can only speculate. Perhaps the add was just a coincidence. Maybe GTalk conversations are monitored for content based targeting just like GMail messages are. There could be any number of reasons.

    The point of this post is that it doesn’t matter how tracking and targeting works online. I believe people prefer ads that are relevant to their interests, but they need to understand how and why ads can be so accurate at times. They also need to have the tools necessary to opt-in or out of this targeting. Without the transparency people will be left to speculate and become more upset about how their privacy is being abused online.

     
  3. IBM Model M Keyboard Collection - On Sale

    It’s time. I’m going to part ways with my small collection of buckling spring IBM Model M keyboards (the original clicky keyboard).

    Why? Well, because I have too many keyboards and I have an upcoming project and want to replenish my PayPal account. I’m going to list them on eBay but I thought I’d list them here just because. So, here they are…

    IBM Model M, Part No 1391401 - Produced on April 8, 1988

    Bid on this keyboard

    This is considered a “white” label IBM Model M keyboard and is fully functional. It has very low yellowing and types very nicely. I’ve used it as my main keyboard for the past two plus years and it’s been very reliable. It has the curly style removable cable and is in great condition. The feet on the back are also in great condition, which is more rare because they’re known to be a weak point. I don’t use them so I haven’t added any wear during my time using it.

    They buyer of this keyboard is going to get a very well taken care of keyboard that is very likely to out last the machine he/she will use it on.

    Here are a couple of images:

    An image of the label - part number and production date.

    I will post back a link to the auction as soon as it’s up. If you’re interested in purchasing it outside of the auction then please comment below or reach out to me on Google+ and we’ll see if we can work out a deal.

    IBM Model M, Part No 52G9685 - Produced on January 4, 1996

    Bid on this keyboard

    This keyboard is also technically a IBM Model M, but in the later years these keyboards were produced by Lexmark for IBM, as you’ll see in the images of the back label below. With that said, this keyboard works very well. There are three main differences between this keyboard and the older “white” label Model Ms:

    1. The key caps are not removable. Most of the time this isn’t a big deal, in fact it makes the caps much more difficult to lose. It also makes them a lot harder to clean.
    2. The cable isn’t detachable. This really only becomes a problem if the cable it’s self breaks.
    3. While the keypress is still very clicky, it’s also a bit more soft. This is either appealing or not. It really just depends on your personal typing preference.

    While this keyboard is a bit less rare than the other two I’m selling, it is bound to have fewer keystrokes and is almost a decade newer. It’s a very reliable keyboard and all the keys feel consistent type nicely. I’ve used this keyboard for the past year and a half at work. The one thing that’s wrong with it is that one of the feet is broken. It never bothered me because as I mentioned above, I don’t use the feet.

    Here are a couple pictures:

    Again, I’ll post a link to it once it’s up on eBay.

    IBM Model M, Part No 1391401 - Produced on June 7, 1987

    Bid on this keyboard

    This is the final IBM Model M I have to offer. It’s the oldest one and share many of the same features of the first one posted above. It’s considered a “white” label and is almost as old as I am…

    It has the curly detachable cable that’s in great shape. It has fully removable key caps for easy cleaning. It has strong buckling spring keys that are very clicky. It’s exterior is in great condition. The only blemish on this one is that the enter key on the number pad isn’t balanced properly because one of the support pieces is missing. It’s very likely that it can be repaired later, but even in it’s current state it can be used. Other than that, this keyboard is in great shape despite it being 25 years old!

    I haven’t used this one much at all. For the past six months or so it has just been sitting in my closet. It’s time to go. This keyboard was meant to be used.

    Here are a couple images:

    Once again, I’ll post the link when it’s up on eBay. If you’d like to reach out and make an offer ahead of time please feel free to contact me on Google+. There’s a link in the left navigation of this site.

    Please let me know if you have any questions about any of the keyboards listed here.

     
  4. Magento: Automatically Apply a Coupon Code w/ jQuery

    I started working on planning a promotion a couple of days ago that would require a discount to be applied automatically. The site runs on Magento, which has very sophisticated coupon code and discounting tools. But this time, none of the built in options quite suited my needs.

    tl;dr; - I needed to apply a coupon code to a customer’s cart, before they actually had anything in their cart and without the visitor doing anything more than visiting a specific landing page. I was able to accomplish my goal with a little creativity, jQuery and determination. And, I don’t know PHP so this is a front end solution using jQuery and cookies. Read on for the code and how it works…

    How to Setup a Discount in Magento

    The first thing you’ll need to do is setup a coupon code with an associated discount of some type in Magento. It doesn’t really matter what type of coupon it is, you just need something to test with. I’m not going to explain how to do that here but for demonstration’s sake, I’ll assume that the coupon code you’ve chosen is testcouponcode and it gives the customer 20% off.

    Don’t be confused. Even though we’re setting up a coupon code, we’re not going to require any action from the visitor. We’re just going to use the back-end coupon capabilities of Magento to do the discounting in the shopping cart.

    Before we go any further, make sure you manually test the coupon code you setup by going into the cart and applying it the old fashioned way. Trust me that if you made a mistake, it’s much easier to discover and correct it at this stage.

    A Few More Notes About Coupons in Magento

    • When the customer enters a coupon code and clicks the apply coupon button, the code makes a HTTP POST to /checkout/cart/couponPost/ with the following data - remove=0&coupon_code=testcouponcode.
    • A coupon code cannot be applied to the shopping cart if there are no items in the visitor’s cart.
    • In my case, if the customer doesn’t checkout during the same session then I don’t want the discount to apply.

    With those three things in mind, let’s dive into how I’ve solved this problem.

    “Apply” Discount on the Landing Page, well Kinda…

    Remember the introduction - I want to apply a discount based on the landing page. However, in Magento, this is technically impossible. You cannot apply the coupon code to trigger the discount right away on the landing page. Since it’s the first page your visitor will have hit, the visitor will have zero items in their cart and that’s the problem.

    No worries though, there’s a way around that. All you have to do is create a session cookie that can be referenced if the visitor does end up putting items into his/her cart. The trigger will be the same (the landing page), but applying the discount will be technically deferred.

    To make the order of events easy to understand, here’s a list:

    1. Visitor hits the special landing page.
    2. Javascript on the page sets a special session cookie, signifying that a discount should be applied once an item has been added to the cart. This cookie will automatically be deleted when the session ends.
    3. Once the visitor views his/her cart (and there are one or more items in it), Javascript on the shopping cart page will make a POST to apply the coupon code that was specified back on that special landing page. This POST will happen in the background and then refresh the page quickly.

    Pretty simple right? Based on those three events, there will be two different blocks of code needed to make this work. One needs to be on the landing page and the other needs to be on the shopping cart view page.

    jQuery for the Landing Page

    Remember that the only goal for the code on this page is to set a session cookie that can be read and referenced later. I’m a newb when it comes to Javascript and for most things I use jQuery. Unfortunately there’s no built in way to write or read cookies in jQuery. The good news is that there’s a really great plugin for it and using the plugin is as easy as downloading it and including it in the HTML of your site. You can get it here, hosted on Google Code.

    Here’s the code:

    <script type="text/javascript" src="/path/to/js/jquery.cookies.2.2.0.min.js"></script>
    <script type="text/javascript">
        jQuery.cookies.set('nameOfCookie', 'testcouponcode', '/');
    </script>
    

    It’s really simple. All you have to do is name the cookie, give it a value and set the path that the cookie should be valid for. Setting a path of / means that it can be read or modified anywhere on the domain. I recommend making the value of the cookie equal to the actual coupon code. It’s most simple that way and I don’t think there’s any reason to try to hide it.

    Once you’ve downloaded the cookies plugin and included this code on your page, it’s a good idea to load the page and inspect your cookies to make sure the cookie was actually set. If it was, move on to the next step.

    jQuery for the Shopping Cart View Page

    This is the code you’ll need to put on the cart view page. The simplest way to implement this is to put it just before the closing <body> tag on the cart view page.

    <script type="text/javascript">
        var emptyCart = jQuery('.cart-empty').text();
        if ( (emptyCart == "") ) {
            jQuery.getScript('/path/to/js/jquery.cookies.2.2.0.min.js', function() {
                var couponCode = jQuery.cookies.get('nameOfCookie');
                if ( (/../i.test(couponCode)) && (!!couponCode) ) {
                    var postData = "remove=0&coupon_code=" + couponCode;
                    jQuery.post("/checkout/cart/couponPost/", postData, function() {
                        jQuery.cookies.del('nameOfCookie');
                        document.location = '/checkout/cart/';
                    });
                };
            });
        };
    </script>
    

    If you cannot add code to this page, you can place it in a file and include it in the head of the page. If you do that though, you’ll want to slightly modify it to execute after the page load is complete. You’ll also want to make sure that it only executes on the /checkout/cart/ page. It would look something like this…

    window.onload = function() {
        var emptyCart = jQuery('.cart-empty').text();
        if ( (/\/checkout\/cart\//i.test(page)) && (emptyCart == "") ) {
            jQuery.getScript('/path/to/js/jquery.cookies.2.2.0.min.js', function() {
                var couponCode = jQuery.cookies.get('nameOfCookie');
                if ( (/../i.test(couponCode)) && (!!couponCode) ) {
                    var postData = "remove=0&coupon_code=" + couponCode;
                    jQuery.post("/checkout/cart/couponPost/", postData, function() {
                        jQuery.cookies.del('nameOfCookie');
                        document.location = '/checkout/cart/';
                    });
                };
            });
        };
    };
    

    Here’s a quick explanation of what the code does:

    1. If you remember, a coupon code cannot be applied to a cart if there aren’t any items in the cart. The first part of the script grabs the text from the headline with a class equal to .cart-empty and it’s stored in the variable emptyCart.
    2. The following IF statement checks to make sure the emptyCart variable is empty. If it isn’t empty then that means the cart is empty and the rest of the code should not execute. If you used the second version, there’s also a condition that makes sure that the current document is the cart view page.
    3. Next, we need to make sure that the jQuery cookies plugin has been loaded.
    4. After the cookie plugin has loaded, the variable of couponCode gets set to the value of the coupon code from the landing page.
    5. Then there’s another IF statement that checks to see if a coupon code exists.
    6. If the coupon code does exist, then the next part makes a POST to /checkout/cart/couponPost/ with a query string equal to remove=0&coupon_code=testcouponcode which will actually activate the discount for the customer’s shopping cart.
    7. If that POST is successful, the cookie gets deleted and the page refreshes. The refresh is needed to let the customer see the discount in the sub-total. It’s unfortunate that the page refresh is necessary. I just haven’t been able to figure out a way to get around it. If you know how, please feel free to comment.

    I hope this has been helpful. Now, go forth and rockout some new landing pages!