Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: coding

  • Stop Using Copy Protection

    Stop Using Copy Protection

    I’ve seen a million features out there to ‘prevent people from stealing your content.’ The idea is that by preventing people from (easily) copying your work, you stop them from stealing it and profiting off your efforts. You may even think that you’re saving your images from being stolen. In general, they use javascript to prevent things like right-click, view source, copying text, and disabling keyboard short cuts. In general, they suck and here’s why.

    User Experience

    Anyone who uses a screenreader or an alternative mouse tool now, officially, hates you. You’ve made your site look like absolute crap. Some screen readers can no longer read your content at all. Also not everything handles javascript very well (which is by far the ‘most popular’ way to block out content) and that makes for a pretty lousy experience for your visitors.

    Support

    If you have a problem with your website and ask the world at large for help, they will take one look and hate you. No one can easily help you with your CSS or your layouts or your design now, because you’re protecting content. When customers ask for help, the first thing I do is turn those plugins off so I can use my normal debugging methods and not worry about cruft interference.

    It Doesn’t Work

    If you disable right-click, you make it harder for me to bring up Chrome’s dev tools, but not impossible. You can’t make it impossible. This is, in part, because there are so many different browsers to account for, but also because developers really don’t want you to be able to kill dev tools. We need them to fix the web, and if I were to leave the dev tools open and then visit your site I would be able to have it open on your site.

    Once I have dev tools open, I can view the resources loaded by your page. Take Instagram, who doesn’t let you right-click on an image to download. I can instead right-click, chose ‘Inspect Element’ and I get this:

    element.style {
        background-image: url(http://photos-g.ak.instagram.com/hphotos-ak-xaf1/t51.2885-11/10912600_6619567248918_1818171895_n.jpg);
    }
    

    Guess what I can do now? Load that URL in another window, download, done. If that’s not available, I’ll go over to the Resources tab, open up the Instagram folder, then Images, and find the image I want. Again, done.

    There’s Only One Way

    There is but one foolproof way to prevent your content from being stolen: Don’t publish it.

    But of course no one wants to hear that. So what’s the other way? Well give up on not having your words stolen. Even if you make it difficult, people will get at it. People type up books and scripts today, they’ll do it for your website if they’re properly motivated. Images, on the other hand, are a different issue. If you’re a photographer, don’t put your full-sized images online unless you’re selling them. And if you are selling photographs, put them on a cloud host like Amazon. Large files and PHP aren’t the best of friends anyway. Your website, unless it’s a store, doesn’t need the 10meg image file.

    As much as it pains me to say it, DRM is also a solution. So is watermarking your images. The way people like Getty protect their images is to lock it down to purchased users only. You can (fairly easily) download the smaller, sample images, but the awesome big ones are locked down.

    But that’s how you protect your content. Not with those plugins.

  • A Case For Hello Dolly

    A Case For Hello Dolly

    I like it.

    I never use it, but I like it.

    I delete it, but I like it.

    It’s not professional, it’s not beautiful, and it’s not something that makes WordPress look grown up.

    And I think needs to stay in the core download of WordPress.

    Let me tell you a story of you. Let me remind you of yourself. Not the you of today who knows all amazing things. Remember the you who was young and inventive but inexperienced. The you who knew how to throw a football but couldn’t throw a spiral. Or you knew how to drive a car and not stick shift. The you who delighted when you learned all those things, like a child with a new toy.

    That you was not professional yet. That you needed an example for how to do new things. You had teachers and friends and parents who showed you the ropes.

    That’s what “Hello Dolly” is. Hello Dolly is the Hello World of WordPress, and it makes a plugin suddenly seem like a non-insurmountable task. We can all look at that one file and see either inspiration for code we can make, or a sudden lack of terror for what WordPress is. Like I tell people in training classes, WordPress is just files, folks. A plugin can be just that file. And you can take the idea and run with it. More than just a training tool, it’s the epitome of open source. It’s code, freely given, than serves as a first step for people who come to WordPress with no formal education. It’s free. It embraces the goals we want to see in open sourced code.

    So it needs to stay in WordPress, because you needed it once. Does it make an annoying extra step for you to delete it when you’re installing WordPress for your clients? Maybe, but for me it makes a moment where I can look back at myself from 2009 and see how far I’ve come from the woman who was too scared to speak at a WordCamp to become a WordPress professional.

    I’ll take that one extra step and never forget where I came from.

  • Gallery Columns Zero

    Gallery Columns Zero

    I have a site where I love using galleries but I hate having to define their width. That’s something I hate about WordPress’ Gallery shortcode, you have to define a width, otherwise it’s all one column. Ugly ugly.

    The way that WordPress handles these columns also sucks. It puts in clear breaks:

    <br style="clear: both" />
    

    And frankly I hate that too.

    But I don’t do that with this other software I use. In fact, I have it all nicely coded in to show all my images, and then toss one final clear break at the bottom, to … clear the breaks. And what that does for me is gives me an adaptive width gallery that will expand and contract with my content.

    So how can I do that with WordPress?

    The easy part is something I already do in EDD, and that’s to use a fake column value of zero: gallery columns="0"

    That gives me a handy new column class: gallery-columns-0

    And that is very easy for me to style, by overriding the width from 100% to auto (the !important is dreadful), and set up the padding I want.

    /* Gallery */
    
    .gallery-columns-0 dl.gallery-item {
    	width: auto!important;
    	padding: 0;
    	margin: 0 10px 0 0;
    }
    

    But what about the ‘break’ afterwards? If you only need to support IE 8 and up, then it’s as simple as this CSS:

    .gallery-columns-0:after {
    	content: "";
    	display: table;
    	clear: both;
    	padding-bottom: 10px;
    }
    

    The padding on the bottom is to make it match my site, adjust as needed. I’m sure I could use the post_gallery filter hook and the same code from the gallery_shortcode function but with my br modification, but 0.017% of people visit this site using IE 7 or less, and at that percentage, so much of the site will look terrible anyway.

    The only real downside is that I have to manually enter the shortcode in text mode, since I can’t select ‘0’ as an option from the dropdown.

  • Subdomains and Subfolders, One Network

    Subdomains and Subfolders, One Network

    For the longest time, if someone wanted to have example.com, foo.example.com and example.com/bar for their Network on Multisite, I’d tell them to use a Multinetwork Plugin like Networks+ (which you can buy from e-Books by Ron and Andrea) or WP Multi Network (free from JJJ).

    But sometimes you don’t need multiple networks and the multiple admin sections. Sometimes you just want to have options. Thanks to the work that started with the roadmap you can have your cake and eat it too.

    If you’ll recall, I detailed how you can map a domain without a plugin on Multisite these days. Guess what? You can also do this with subfolders and subdomains.

    I did this with a subdomain install, since it made more sense to go that way.

    WordPress is installed at multisite.dev and I have subsites of foo.multisite.dev and bar.multisite.dev

    I then made a new site called baz.multisite.dev:

    Creating baz.multisite.dev

    Then I edited that from this:

    Editing baz.multsite.dev

    To this:

    Now it's multisite.dev/baz

    Be careful here! If you don’t put the trailing slash on the folder name, this will not work. And does this work? Yes it does. Of course there is the small issue of how this looks on my list of domains:

    Domain List is Ugly

    I have two sites as ‘multisite.dev’ and I have two ‘foo’ sites (because you can also make foo.multisite.dev/zot if you want to). The problem is that the Sites page in the Network Admin has a check:

    $blogname_columns = ( is_subdomain_install() ) ? __( 'Domain' ) : __( 'Path' );

    This means the ‘domain’ of foo.multisite.dev/zot and foo.multisite.dev are (correctly) foo. I couldn’t see how to filter, so I made a quick MU Plugin:

    class Add_Blog_Blogname {
    	
    	public function __construct() {
            add_filter( 'wpmu_blogs_columns', array( $this, 'blogname' ) );
            add_action('manage_sites_custom_column',  array( $this, 'blogname_columns' ) , 10, 3);
            add_action('manage_blogs_custom_column', array( $this, 'blogname_columns' ) , 10, 3);
        }
    
    	function blogname_columns($column, $blog_id) {
    	        global $wpdb;
    	        
    	        $blog_details = get_blog_details($blog_id);
    	        
    	        if ( $column == 'my_blogname' ) {
    	                echo $blog_details->blogname;
    	        }
    	        return $value;
    	}
    	
    	// Add in a column header
    	function blogname($columns) {
    	    $columns['my_blogname'] = __('True BlogName');
    	    return $columns;
    	}
    }
    
    new Add_Blog_Blogname();
    

    This tosses the True Blog Name to the end of the sites list. It’s not perfect, but it gets the job done.

  • GeoIP Options

    GeoIP Options

    Thanks to crazy thinks like the EU VAT laws, sometimes we really have to know where people are coming from when they visit our sites. The problem with this is … how?

    There’s a cool extension for PHP called GeoIP, which I’ve finally installed on this server (along with my upgrade to PHP 5.5 and some other things, yes, still on Apache, shut up Otto). The extension comes from MaxMind, who also have a pure PHP version you can use. I’m not because the GeoLite2 databases are distributed under the Creative Commons Attribution-ShareAlike 3.0 Unported License and that means I can’t include it in a WordPress plugin.

    But that really made me wonder why it was okay not to attribute Maxmind when I used it via Pecl. I mean, technically I should, right? But where and how? I ended up putting a note in my site footer, to say that the site used the Maxmind DBs, but I haven’t included any note about that in my plugin since the DBs are included in the plugin, just called if the functions are found. It’s on you to install and attribute as needed.

    Installing mod_geoip

    Installing this is simple, from a server admin perspective.

    Since you can’t use the yum install on Apache 2.4, I got to use a cPanel Custom Module, which meant running this:

    wget http://easyapache.cpanel.net/optmods/custom_opt_mod-mod_geoip.tar.gz
    tar -C /var/cpanel/easy/apache/custom_opt_mods -xzf custom_opt_mod-mod_geoip.tar.gz
    

    And then I ran an EasyApache build. That was fine, I needed to do that anyway. Once that was done, I installed the pecl for GeoIP:

    pecl install geoip
    

    Done. Optionally you can add it to apache in either your .htaccess or (better) a conf file for your whole server:

    <IfModule mod_geoip.c>
      GeoIPEnable On
      GeoIPDBFile /usr/local/share/GeoIP/GeoIP.dat
    </IfModule> 
    

    What about upgrades?

    Every month you don’t upgrade your geoIP DB, the more your site sucks. Someone quoted a statistic that every month you don’t upgrade the DB, the accuracy drops by 1.5%. I can’t validate that, but I’d believe it.

    Upgrades are fairly painless, thanks to geoipupdate, though it doesn’t include the IPv6 files for some reason. Still, being able to toss this into crontab makes my life easier:

    38 15 * * 5 /usr/local/bin/geoipupdate
    

    Of course… I did notice that there’s a new MaxMind DB Apache Module.

    If you’re on nginx, you can grab the nginx geoip module too.

    What if I can’t install PHP modules?

    By request, I’d already added in the GeoIP2 PHP API to my wee little plugin. Not everyone can use mod_geoip or mod_maxminddb, after all, so it’s good to have options. And with this option, you have the question of how to update since geoipupdate won’t work anymore.

    If you want to go hardcore, you can Auto-update your GeoIP databases with Cron via that very robust script. Or if you’re simple like me, it’s a geoip.sh script in your ~/scripts/ folder:

    #!/bin/sh
    cd /home/username/public_html/wp-content/edd-pec-geoip
    wget -q http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz
    gzip -d -f GeoLite2-Country.mmdb.gz
    

    And then I have this in my crontab:

    30 22 2 * * /home/username/scripts/geoip.sh
    

    Which is a lot easier for a lot of people.

  • Mailbag: Multiple Download Buttons

    Mailbag: Multiple Download Buttons

    Less a mailbag and more a forum question that grew from a logical question.

    How do you link ‘external’ stores from your product pages?

    Well, for me I do it by having a custom page I designed for my products, and listing three shortcodes. One for EDD (the default [purchase_link]) and then two for my own links. In non-shortcode, its like this:

    [Buy from Me][Buy from Amazon][Buy from Apple]

    The actual code is below. I try to keep things as simple as I can when I do this, and I did nick a bit of code from EDD core (you’re supposed to) to make it match. All this does is the most basic of links and it all fits in a nice little box like this:

    The sales box sits on the upper rght of the page and lists image, price,  and links.

    I like that layout. Reminds you a bit of Amazon, and there’s a reason. If you keep the space open and clear, it’s easy for a visitor to grasp their options. Also I can put below a link to my EU/VAT page and say this “Purchase disabled? Here’s why…” I don’t right now, though I probably should. I couldn’t think of how to elegantly handle making the button a link like that.

    The code

    	// EDD Buy Externally [edd_external store="iTunes" link="http://apple.com/foo" text="Add to Cart" ]
    	function edd_external_shortcode_func( $atts ) {
    		global $edd_options;
    
    	    $atts = shortcode_atts( array(
    	        'store' => '',
    	        'link'  => '',
    	        'text'	=> 'Buy Via',
    			'style' => isset( $edd_options[ 'button_style' ] ) ? $edd_options[ 'button_style' ] : 'button',
    			'color' => isset( $edd_options[ 'checkout_color' ] ) ? $edd_options[ 'checkout_color' ] : 'blue',
    			'class' => 'edd-submit'
    	    ),
    	    $atts, 'edd_external' );
    
    		// Override color if color == inherit
    		if( isset( $atts['color'] )	) {
    			$atts['color'] = ( $atts['color'] == 'inherit' ) ? '' : $atts['color'];
    		}
    
    		$content = '<a href="'.$atts&#91;'link'&#93;.'" class="edd-external edd-'.$atts&#91;'store'&#93;.'
    		 '.$atts&#91;'style'&#93;.' '.$atts&#91;'color'&#93;.' '.$atts&#91;'class'&#93;.'
    		"><span class="edd-add-to-cart-label">'.$atts['text'].' '.$atts['store'].'</a></span>';
    
    		return '<div class="edd_purchase_submit_wrapper">'.$content.'</div>';
    	}
    
    	add_shortcode( 'edd_external', 'edd_external_shortcode_func' );
    

    Like I said. Pretty basic.