Half-Elf on Tech

Thoughts From a Professional Lesbian

Author: Ipstenu (Mika Epstein)

  • FUD: The Sky Is Not Falling

    FUD: The Sky Is Not Falling

    Every day it seems like there’s a new Zero Day vulnerability about our websites. SSL is being deprecated, PHP is out of date, the CMS we use has a critical vulnerability, security isn’t all that safe, and OMG we’re all going to get our identities stolen and our lives hacked.

    Making matters worse are those myriad security tools we use to keep ourselves from getting hacked or attacked, and they alert us to horrible things. I say worse because they terrify people without actually explaining and educating them, so the uninformed users come running to complain the sky is falling. And when those people are told an answer by other experts, they don’t know who to believe.

    Can you blame them?

    Responsible Disclosure

    It’s four years now, and Nacin’s post about how security is nuanced is still required reading.

    The problem we face is that telling the world about a security issue is complicated. We definitely need to tell people who are responsible for fixing it, and in a perfect world we should trust that they’ll push out that fix in a reasonable time frame. We also should be able to trust they’ll tell the appropriate people.

    But who, exactly, is the appropriate person to tell about a Drupal patch? Not the hack, the patch. In a different light, who are the right people to tell that a new security fix for an operating system has been released?

    There are millions of users. How do you get to all of them quickly, with the right amount of information so they can understand how important this patch is to them, and how quickly they should apply it?

    Enter Security Companies

    Many companies make their milk and meat off being the people who monitor and announce security releases. There’s nothing wrong with this. In fact, I laud them for being a much needed service. With so much data flowing, it’s important to have a service that can help users winnow down what’s critical to them and their setups.

    But… That’s not what’s happening.

    Security companies face the same problem we do. There’s just too much data, and it’s being updated all the damn time, and there’s no way to keep up with all of it. Which means that they do what I tend to do when I’m trying to explain things to a wide variety of people. They simplify as much as possible.

    The problem with simplification is that you have to skip over things and leave out the nuances that help people understand what’s actually going on. They have no idea what they actually need to worry about. And we’re back to zero.

    To Know When To Worry …

    You have to actually understand context to know what to worry about.

    There’s literally no other way around it. There’s no shortcut, there’s no cheat sheet, there’s just knowing what your site is doing.

    Let’s taken OpenSSL as an example. Back in 2014, a serious issue called HeartBleed was discovered. The bug was phenomenal in that it allowed people to steal and read secure data. If you ran a website, this was a massive issue. For your webhost.

    Was it a huge issue to you? Well. Maybe.

    A lot of people sounded the alarm and declared this a crisis, and we should all grab our web hosts and asks what they were doing and when would we be fixed. And the rest of us said “Hang on. Webhosts are aware. See if they have an announcement, which most will, and if they say they’re working on it, trust them.”

    Sounds like I’m passing the buck, but the reality is that unless I’m using my site for privileged data (like a private blog, or a store), then the odds are for my individual site … I don’t need to panic. Especially if I use unique passwords and take regular backups.

    This doesn’t mean Heartbleed wasn’t a huge problem, and that I didn’t want to see my host putting this as their number one priority, but it means that I’m aware of the risk (private data being stolen) and the likelihood of it happening (moderate to high) and the level of risk. That last one is the most important.

    What’s the worst that could happen, today, on this site if someone stole private data? Well. They’d see my password maybe, and some draft posts, and have access to my API keys for a couple services. Nothing I can’t fix relatively quickly. They can’t log in to those API services and they can’t destroy my life.

    If I was still running a store (like I was at the time of the initial vulnerability), I paid close attention to the fixes being released and the moment one was out for my system, applied it. But there was no need to panic or rush about. I understood what was going on.

    If You Don’t Know …

    If, however, you have no idea how it all works and what it means, then I recommend the following checklist:

    1. Do I have good passwords?
    2. Do I have good backups?
    3. Does my web host have a reliable track record for fixing this stuff?
    4. Do I run any private/privileged data on my site that could be dangerous to release to the public?

    If that last item is 4, then I better be paying my host (or an expert) a lot to protect me ASAP. If you’re still on budget web hosting, it’s time to move up to something managed, or hire someone to manage for you.

    Otherwise, if the first three are all ‘yes’ then I’m not going to panic. I’m going to trust in the experts to do their job.

  • It’s Just Math

    It’s Just Math

    Recently I posted about how I added new features to a show scoring system, over on LezWatchTV. We added in what we call Intersectionality, which is rewarding shows for positive representation of diversity in the world. Naturally that begs the question of what is show scoring (answer: it’s calculative a qualitative value of how good a TV show on a scale of 0-100). And that makes people ask …

    How do you do that?

    It’s really math

    Look, the bare answer to all of this is that it’s math. I’m taking the meta data we assign to shows, like how much screen time characters get and how good the show is for them, and so on, and assigning numbers to those values. Then I add up the numbers, in various ways, and determine what the over all score is.

    It’s a little more complex than that, and if you’re super interested in how it all works, we wrote up an explanation as to the framework I created to value shows.

    But most people who ask me how I did this aren’t asking about the math, they want to know about the code. That is, how did I get WordPress to automate all this, because you know I don’t do it all by hand. No, I do it when the post saves.

    Magical Hooks

    Let’s take a moment. What’s a hook anyway?

    A hook is an action or a filter in WordPress, which allows you to write code that ‘hooks’ into the rest of WordPress code. You can use this to trigger your code to run at specific times.

    For example, if I had a hook called publish_post (which we do – WordPress has that built in), and I wanted to run my show calculations when I publish a post, I would do this:

    add_action ( 'publish_post', 'shows_calculations' );

    That would of course require me to have a function called show_calculations() that does the math, which is fine. But. I don’t want to do this on post publish. I want to do it on post save, and only if the post is of the shows post type. And that sounds like a lot of if/then statements until you learn about dynamic hooks.

    You see, I’m using the save_post_ hook, which runs when a post is saved, and it’s a little special. Unlike a hook like publish_post(), this hook lets me customize it how I want by being save_post_{$post->post_type} …

    Yeah those curly brackets are weird, right? That’s the dynamic part. That part changes.

    Dynamic Saving

    To understand how the hook name changes, you should know that in my case, I have a post type called post_type_shows — logical right? Well the subsequent hook is called save_post_post_type_shows — that is, I’ve replaced those weird brackets with the post type.

    Once you know your new hook name, it’s like every other hook:

    add_action( 'save_post_post_type_shows', 'shows_calculations', 10, 3 );

    What that does is call the function post_type_shows_calculations on every post save. And that function calls another one I called do_the_math() which passes the post ID to the myriad complications of calculations I perform.

    But the magic literally is in that post save hook.

  • NoEmbed: Embedding What’s Not oEmbed

    NoEmbed: Embedding What’s Not oEmbed

    We all love oEmbed with WordPress. Want to include a YouTube video? Paste in the URL and call it a day!

    The magic is that WordPress sends data to the YouTube oembed endpoint (i.e. a special app on YouTube that translates URLs to embed things) and says “Hi, I have this video URL here, what can I use to embed it?” And YouTube replies back “This javascript, my fine friend!” WordPress tips it hat and carries on, swapping the URL out for javascript on the fly.

    Awesome.

    Except when it doesn’t work because it can’t because there isn’t an oEmbed endpoint.

    What Now?

    Usually I make a shortcode. But my man Otto always grumbles and tells me to make an embed instead.

    The concept of the embed is that we register a ‘fake’ oembed. It’s not an endpoint, it’s just saying “Hey, WordPress. When you see this kind of URL all alone, let’s make magic.”

    It’s surprisingly straightforward. All we need to know are two things:

    1. What is the URL people are going to paste in?
    2. What is the output supposed to look like?

    Since we’ve already done this as a shortcode, we’re ready to go.

    Register the Handler

    First we have to tell it that we’re making a new handler, called indiegogo and this is the kind of URL to expect:

    wp_embed_register_handler( 'indiegogo', '#https?://www\.indiegogo\.com/projects/.*#i', 'indiegogo_embed_handler' );
    

    The first part, indiegogo, is the name. It should be unique.

    The second part, '#https?://www\.indiegogo\.com/projects/.*#i' is saying “http OR https” and “as long as the URL starts with www.indigogo.com/projects” — it’s ‘basic’ regex.

    The last bit, indiegogo_embed_handler is the function name we’re going to need.

    Write the Embed Function

    This is very similar to the shortcode. We take the data, make sure it’s formatted correctly, and output the (in this case) iFrame:

    function indiegogo_embed_handler( $matches, $attr, $url, $rawattr ) {
    	$url   = esc_url( $matches[0] );
    	$url   = rtrim( $url, "#/");
    	$url   = str_replace( 'projects/', 'project/', $url );
    	$embed = sprintf( '<iframe src="%1$s/embedded" width="222" height="445" frameborder="0" scrolling="no"></iframe>', $url );
    	return apply_filters( 'indiegogo_embed', $embed, $matches, $attr, $url, $rawattr );
    }
    

    I’ve left the filters in place in case I decide I want to do more weird things to it, without having to edit the core part of my code.

    A GutenGotcha

    For some reason, this doesn’t work in Gutenberg, and it tells me it cannot embed the content. Except when you visit the page, everything is embedded perfectly.

  • A Slightly More Complex Sample Box: Spoilers

    A Slightly More Complex Sample Box: Spoilers

    Round two!

    Once I made a simple, sample spoiler box, it was time to jump into the next stage. Customizable, editable, not simple, sample spoiler boxes!

    Here’s the best part. All I had to change was the index.js file from the previous example.

    The Javascript

    ( function( blocks, i18n, element ) {
    	var el = element.createElement;
    	var __ = i18n.__;
    	var RichText = blocks.RichText;
    
    	blocks.registerBlockType( 'library/spoilers', {
    
    		title: __( 'Spoiler Warning' ),
    		icon: 'vault',
    		category: 'widgets',
    		supportHTML: false,
    
    		attributes: {
    			content: {
    				type: 'array',
    				source: 'children',
    				selector: 'div',
    			},
    		},
    
    		edit: function( props ) {
    			var content = props.attributes.content || 'Warning: This post contains spoilers!';
    			var focus = props.focus;
    			function onChangeContent( newContent ) {
    				props.setAttributes( { content: newContent } );
    			}
    
    			return el(
    				RichText,
    				{
    					tagName: 'div',
    					className: props.className,
    					onChange: onChangeContent,
    					value: content,
    					focus: focus,
    					onFocus: props.setFocus
    				}
    			);
    		},
    
    		save: function( props ) {
    			return el(
    				'div',
    				{ className: 'alert alert-danger'},
    				props.attributes.content
    			);
    		}
    	} );
    } )(
    	window.wp.blocks,
    	window.wp.i18n,
    	window.wp.element
    );
    

    What’s Different?

    A few things. A lot of things. The idea is that we need to pass the content attribute (i.e. our warning) to be processed. This is very much like how you pass attributes through shortcodes, so don’t panic.

    var content = props.attributes.content || 'Warning: This post contains spoilers!';
    var focus = props.focus;
    function onChangeContent( newContent ) {
    	props.setAttributes( { content: newContent } );
    }
    

    This says “Set the content to ‘Warning: This post contains spoilers!’ if there’s nothing there. Then watch the focus. If the focus changes, use the new content to replace the original content.”

    Down in our return el section, we’ve changed it to be Rich Text (so people can use bold and so on… even though it’s always bold), and the value: content, is the variable content we edited above.

    What’s It Like?

    It’s just like any other Block. It inserts itself when you click the icon, it loads the default, and you can edit it:

    An example Gif of spoilers

    And that is a simple, editable, Gutenberg Block

  • A Sample Block: Spoilers

    A Sample Block: Spoilers

    Before I jump into this, I have to say .. this post was not written in Gutenberg.

    Sadly the plugin I use for code display, when I need it to be colored and easy to read, isn’t yet Gutenberg friendly. And, worse IMO, there’s a bug that causes multiline shortcodes to be smashed into one line, which makes a code block unusable. My two fixes are either the plugin I use be updated (which is beyond my skills at the moment) or I find a new plugin (looking). Or I wait.

    Anyway.

    Let’s make a simple block that you can’t edit!

    There are Four Files Needed

    1. spoilers.php – This is the main PHP file
    2. spoilers/index.js – This is the code
    3. spoilers/editor.css – This formats what you see on the editor
    4. spoilers/style.css – This formats what you see on the front end

    The last two aren’t required but I use them to make things pretty.

    The PHP

    The PHP file will need to be included in your code however you want to do it. I have a file called _blocks.php which includes all my Gutenblocks. In turn, it is included in my plugin’s main file.

    function lp_spoilers_block_init() {
    	$dir = dirname( __FILE__ );
    
    	$index_js = 'spoilers/index.js';
    	wp_register_script(
    		'spoilers-block-editor',
    		plugins_url( $index_js, __FILE__ ),
    		array( 'wp-blocks', 'wp-i18n', 'wp-element' ),
    		filemtime( "$dir/$index_js" )
    	);
    
    	$editor_css = 'spoilers/editor.css';
    	wp_register_style(
    		'spoilers-block-editor',
    		plugins_url( $editor_css, __FILE__ ),
    		array( 'wp-blocks' ),
    		filemtime( "$dir/$editor_css" )
    	);
    
    	$style_css = 'spoilers/style.css';
    	wp_register_style(
    		'spoilers-block',
    		plugins_url( $style_css, __FILE__ ),
    		array( 'wp-blocks' ),
    		filemtime( "$dir/$style_css" )
    	);
    
    	register_block_type( 'library/spoilers', array(
    		'editor_script' => 'spoilers-block-editor',
    		'editor_style'  => 'spoilers-block-editor',
    		'style'         => 'spoilers-block',
    	) );
    }
    add_action( 'init', 'lp_spoilers_block_init' );
    

    The JS

    Here’s the weird stuff. And I’m going to be honest here … I don’t understand all of this yet. But I picked this very simple example because it lets you see what’s going on in a concrete way.

    ( function( wp ) {
    	var registerBlockType = wp.blocks.registerBlockType;
    	var el = wp.element.createElement;
    	var __ = wp.i18n.__;
    
    	registerBlockType( 'library/spoilers', {
    
    		title: __( 'Spoiler Warning' ),
    		icon: 'vault',
    		category: 'widgets',
    		supportHTML: false,
    
    		edit: function( props ) {
    			return el(
    				'div',
    				{ className: props.className },
    				__( 'Warning: This post contains spoilers!' )
    			);
    		},
    
    		save: function() {
    			return el(
    				'div',
    				{ className: 'alert alert-danger'},
    				__( 'Warning: This post contains spoilers!' )
    			);
    		}
    	} );
    } )(
    	window.wp
    );
    

    The CSS

    There are two CSS files.

    editor.css

    .wp-block-library-spoilers {
    	border: 1px dotted #f00;
    	background-color: pink;
    	font-weight: bold;
    }
    

    style.css

    .wp-block-library-spoilers {
    	font-weight: bold;
    }
    

    Back in the js there was a bit that looked like this: { className: props.className },

    That’s what tells it to use these. In addition, I use this to call some theme specific code: { className: 'alert alert-danger'},

    The Output

    On the editor, I see this:

    Example of what the spoiler text looks like on the editor

    I included the block icon so you could see the little vault I used to indicate the block.

    On the front end, everyone sees this:

    A nice looking spoiler warning

    What’s Next?

    Making it editable, of course!

  • When You Need Blocks

    When You Need Blocks

    There are a lot of cases where you don’t need a custom block. My spoiler block (from last week) is a great example of that:

    But. What about when you want to have that spoiler have choices? Now you’re outside the shared content block territory and into the confusing land of Gutenberg plugins.

    Blocks Are Not Simple

    I’m the sort of person who abhors boilerplate plugins. I just do. I feel that they divorce you from understanding what the code is and does, and how it all plays together. The more you rely on them, the less you can debug when it goes sideways. Oh, and it will. It always does.

    But. Gutenberg requires a lot more Javascript than I happen to be good at. Or rather, it requires new Javascript. Which is why I did exactly what I did the first time I ever made any plugin. I went and found one that did mostly what I wanted, and I edited it.

    Whaaaaat? 

    It’s true. And I want everyone to take a moment and realize this is a perfectly normal, okay, thing! In fact, I would like to see Hello Dolly converted to include a Gutenblock because learning by example is a valid, tried and true, way to teach someone how things come together.

    What Examples Are Good?

    Okay so where is a good place to start?

    That’s enough to get you started, I think. I went with WP-CLI since I like it and I’m used to it. Of course, it came with a small problem. In order to make a block via wp-cli, you have to put the code in a plugin (or a theme). Well fine. I did that to scaffold it and then I moved it to where I was developing. Most people aren’t so particular.

    Is It Hard?

    Not really. Once you get used to editing the js file instead of PHP, it’s just like hacking any other plugin. Start with the simple thing. Make a block that just does one thing and isn’t editable. My one tip is that when you call your blocks, make sure to wrap it in a check if the function exists:

    if ( function_exists( 'register_block_type' ) ) {
    	include_once( dirname( __FILE__ ) . '/spoilers.php' );
    }

    Otherwise there’s a chance that a non-Gutensite will die on you.

    Good luck and happy Gutenberging!