Half-Elf on Tech

Thoughts From a Professional Lesbian

Author: Ipstenu (Mika Epstein)

  • Being Aware about Safe Spaces and Self Care

    Being Aware about Safe Spaces and Self Care

    One of the things people complain about is that I will walk away from a conversation that’s going nowhere. This extends to my worklife, and of course my WordPress work. Related to this, I will also choose to not engage with argumentative demands like “Why did you do X?” on places like Twitter and Facebook.

    This is often considered to be cowardly, an admission of wrongdoing, avoidance, or proof I’m not “up” for the job. Sometimes people jump into the special snowflake argument (that is: I am one) or that I’m too sensitive and need a safe space.

    Okay, let me explain why I don’t defend myself, or even generally reply to people who demand explanations.

    Social Media is Unsafe

    I like social media. I like reading thoughts and replying, expressing my own short form feelings, and so on.

    But by its open nature, social media is incredibly dangerous. Anyone can talk to anyone, and if we’ve learned anything from recent days, there are a lot of naive people out there who fall prey to any con man who walks up and tells them it’s not their fault their life sucks.

    It also lends itself to a mob. And mobs are the most dangerous sorts of people. They’ve fallen in truck with a group and they believe everything they’re told. Worse. They are regularly aggressive when they face adversity, and they take justice upon themselves. This means, should you ever happen to upset one of them, you will end up with a mob on your doorstep. Or your DMs.

    A Place For Everything

    Recently, a plugin developer made what should have been an innocuous question. Why was a post moderated. This is the sort of question I get a lot, and in general I press mute and ignore it, because if you want to ask me a question about plugins, there’s an email address you already have. Press reply. And if you want to ask about forums stuff, there’s a channel on Slack.

    The problem here was in the hours leading up to this, he’d also spoken with people about another plugin. This plugin happens to be contentious for many reasons, including overmoderation of bad reviews. Someone decided that one and one meant four, and I was the fault of the reviews being removed.

    I think that if you have questions about a team, you logically ask the team. Or the team management. When you ask someone whom you presume to be the point person on Twitter, you run a risk of a public misfire. You also run a risk of signaling to the mob who their new target is. Which is what accidentally happened that day.

    Angry People are Stressful

    If you’ve ever tried to reason with someone who’s angry, you’ve probably reached a point where you thought it was better to bash your head in than try to explain facts. When you get a mob, it’s even worse. The people start out super angry, they refuse to accept any viewpoint but their own, and they make you angry too. This begins a vicious cycle where you overreact, they get angrier, you get angrier, and bad decisions are made.

    It goes without saying, I’m not exempt from this. I make bad decisions when under anger and stress, same as pretty much everyone. While I strive not to, this is nearly impossible, and that is when I will disengage. Because I can tell I’m not going to be reasonable, and that would be harmful.

    But what changes when you’re the end stop of a team? When you’re the rep and you have no choice but to make the decisions and the hard calls and continue to try? Well, you draw a line about where you will have those conversations. And you draw a line about with whom. Like saying “I won’t do this over Twitter.”

    Say No, Even When You Feel Bad

    The main reason I won’t have a conversation about why decisions are made on Twitter is that there is no accountability for actions.

    Anyone can make an anonymous account and troll people, telling them off for perceived slights. But to take your regular, daily use account and step up to ask a question, in the official location for those discussions, takes courage. More important, it takes a quality of human that will accept responsibility for their actions.

    Most of the time. The odds are at least higher that people will be willing to discuss when they come into a discussion room. Obviously not always, and unlike Twitter I can’t mute or block people who are incapable of accepting ‘no’ as a valid answer.

    Because you see, the main reason I don’t want to have the conversation on Twitter is that I worry you’re going to out yourself. That you will embarrass yourself when I say that leaving a review on the moderators in a plugin review is not appropriate. Or if I explain “You made multiple accounts to leave 5 star reviews on your own plugins.” Or worse, when I have to point out that “You called the moderators Nazi c***s.”

    None of those are made up.

    Emotional Labour

    There’s one more thing.

    When someone walks up to me and demands I explain myself to them, they place a burden on me. Literally they ask me to defend my actions. While the word “explain” is in there, it’s not what they mean. What they mean is for me to justify my actions and choices.

    Usually when I attempt to explain the situation, or if I suggest the one they’re comparing to isn’t the same at all, I get called defensive. Or I’m trying to hide the point.  And I’m expected to do it with a smile. If I call someone out on their inability to reason, I’m a bitch and making excuses. If I’m polite and respectful, I’m hiding something.

    Simply put, if I can’t have a civil, reasonable, conversation with them about it, I’m not going to waste my time. No matter what, they’ve made up their minds going in.

    Now, I will note that after some time doing this, you can tell who is going to be a stubborn jackass and who is not after about two passes. I can tell, on Twitter, from their previous tweets. That’s why I’m quick to mute and block. It’s not to silence them, it’s to sufficiently ignore them and not spend energy on someone who begins a conversation from a place of disrespect.

    None Of This Changed Your Opinions of Me

    If you’re reading this, you’re probably a regular who knows you’re getting an opinionated, open minded, person who looks as intently at herself as she does everything else. In order to be truly honest, I have to be honest about myself, who and what I am, and what I say. 

    The other person who’s reading this probably came from a link someone gave you, following a discussion about my flaws. Let’s be honest, I’m a big fat target for those posts on Twitter, Facebook, and other various blog sites around the planet.

    You both probably got here and thought “Yep, she’s exactly what I thought.”

    Funny how that works.

    I’ll leave you with this relevant article about why YouTube stars are heading for burnout:

    Lees began to feel a knock-on effect on his health. “Human brains really aren’t designed to be interacting with hundreds of people every day,” he says. “When you’ve got thousands of people giving you direct feedback on your work, you really get the sense that something in your mind just snaps. We just aren’t built to handle empathy and sympathy on that scale.” Lees developed a thyroid problem, and began to experience more frequent and persistent stretches of depression. “What started out as being the most fun job imaginable quickly slid into something that felt deeply bleak and lonely,” he says.

    The Guardian 


  • ES5, ESNext, and a Headache

    ES5, ESNext, and a Headache

    You may have noticed, reading the Gutenberg documentation, that there are two ways to add new blocks. There’s ES5 and ESNext. The two code bases are similar, but they certainly can confuse new developers. And while it’s possible to migrate from one to the other, that too can be a bit of a headache.

    Consistently naming versions? HAH!

    Providing a consistent naming pattern is important for people to be able to understand what version of a software they’re using, and what’s next. Whatever you pick, when you decide how to go. you’re pretty much stuck with it forever. There are exceptions, but even Apple and Microsoft had semi-logical explanations for their names. I can’t really justify Windows ME to anyone, though.

    In Open Source land, people love to complain that WordPress itself doesn’t use semantic versioning (aka SemVer). That is, a jump from 4.2 to 4.3 is a major release, where as if it were SemVer, that would be a minor change.

    SemVer uses the concept of MAJOR.MINOR.PATCH with regards to numbers, which means you increment:

    1. MAJOR – when you make incompatible API changes,
    2. MINOR – when you add functionality in a backwards-compatible manner
    3. PATCH – when you make backwards-compatible bug fixes

    WordPress does MAJOR.MAJOR.MINOR-OR-PATCH which really confuses a lot of people, and I understand that.

    Of course, then you look at the history of JavaScript and you cry a little.

    JavaScript isn’t Java, and neither are coffee.

    We have to go back a while here. In 1995, Netscape Navigator was releasing a new coding language called LiveScript. In 1996 they renamed it to JavaScript, presumably to capitalize on the whole ‘Java’ craze. I actually took some Java classes back in those days. Anyway, Netscape tossed the deal over to ECMA International for some standardization, and got us ECMAScript.

    ECMAScript is the language, Javascript is the most popular implementation of the language. Its like HTML and XHTML, and when you get down to brass tacks, most people don’t care. They use the terms interchangeably. And that’s okay.

    From 1996 to around 2010, nothing changed. Javascript trucked along doing what it did, and ECMAScript didn’t change much at all. There was ECMAScript2 and ECMAScript3, but after that, we had a decade of nothing. The astute reader now has gone “ECMAScript… ECMA Script. ES?” And they would be correct.

    What is ESNext?

    ECMAScript 5 (aka ES5) came out in 2009, but really it didn’t get picked up until 2012. This is because of our old nemesis, Internet Explorer. In the last 6 years, developers have pretty much stuck to ES5, since it works in all modern browsers. We have ES6, also known as ES2015, but not every browser supports it yet. Which is why we have ESNext.

    To put it simply, ESNext (or ES.Next) is the future version of ECMAScript which is yet to be released. If you hear ES7 or ES2016, that’s actually the same thing. The naming system is a little janky and confusing, if you hadn’t already noticed.

    And this is why you’ll hear it called ESNext in WordPress. It encompasses ES6/ES2015, ES7/ES2016, and whatever comes next. Aaaaaah you see? 

    ES4 was abandoned by the way.

    It’s Not Dangerous.

    While not all browsers support ESNext, there’s good news for WordPress. It doesn’t matter because we transpile (I’ll get there in a second). For WordPress and Gutenberg, the primary difference is going to be in the ‘style’ of code and the build process. The break down is as follows:

    • ES5 is more obscure to write, but runs immediately
    • ESNext is more clean to write, but requires post compilation (transpilation) to run Gutenberg

    That probably didn’t help. Okay, how about this. There a way to write CSS (called SASS) which lets you add programatic features to your CSS. ES5 and ESNext are the same way. You totally can write ESNext without compiling, but not yet for Gutenberg. This is kind of the same thing, except when we transpile ESNext, we’re converting it to ES5.

    Now, we use ES5 in the end for a couple reasons, but primarily it’s because Gutenberg uses React, and React JSX (which translates Javascript to XHTML). That requires us to transpile back to ES5 in order to be used by all browsers. For now.

    Browsers update a lot faster than they did when we were trying to get rid of IE5. Still, Internet Explorer is around and will be for a while at financial institutions, so don’t get super excited yet.

    Where does this leave us?

    When you go to write your first Gutenblocks, I recommend ES5 for the simple ones and ESNext for the complex ones. ESNext is more semantic, in that it’s laid out in a more human readable way. ES5 is faster to edit and test.

  • Blocks: Another Way to Adjust Settings

    Blocks: Another Way to Adjust Settings

    As I’ve mentioned a few times, one of the ways you can adjust settings on a block in Gutenberg is via the sidebar. In fact, this is the default way most people will interact with block settings.

    If you make a paragraph today, you can see it like this:

    This is the default paragraph sidebar from Gutenberg. No customizations.

    But. I don’t actually like it very much. I appreciate that I have it, and I love that I can get it out of the way. But sometimes I like settings to be a little more contextual.

    It’s Easy to Add Sidebar Settings

    One of the reasons we all use sidebar settings is that, well, they’re easy. When I built out my listicles plugin, I could use the inspector controls and automagically I have my own settings.

    This:

    <InspectorControls>
    	<PanelBody title={ 'Listicle Settings' }>
    		<RangeControl
    			label={ 'Items' }
    			value={ items }
    			onChange={ ( value ) => setAttributes( { items: value } ) }
    			min={ 1 }
    			max={ MAX_ITEMS }
    		/>
    		<ToggleControl
    			label={ 'Reversed' }
    			help={ ( checked ) => checked ? 'Reversed order (10 - 1)' : 'Numerical order (1 - 10)' }
    			checked={ props.attributes.reversed }
    			onChange={ () => props.setAttributes( { reversed: ! props.attributes.reversed } ) }
    		/>
    	</PanelBody>
    </InspectorControls>

    Looks like this:

    A screenshot of the listicle settings, which are a slider for the items and a toggle to reverse the order display.

    But like I said, I don’t like it very much. It’s clunky, it’s touchy, if you delete the number and type in a new one it’ll wipe all your data. And worst of all, my partner in crime, Tracy, hates it. If your work partners hate a tool, then it’s serious problem. I’ll put up with annoyances to me, but I’ll learn new code for the team.

    Think About What’s Easier

    Before I get into the code I used to solve the issue, I want to take a moment to talk about theory and understanding usage.

    One of the critiques about Gutenberg is that it’s changing too much too quickly, and it’s not listening to users. The problem with that complaint is it lacks context. I’m big on context because I believe that only with understanding the usage and context can we as a whole make the correct decisions going forward. What changes, when, and why depends entirely on what’s being used, for what, and why.

    It’s much more direct to understand this when I look at my little listicles block. You see, we use it for one thing: to make lists with a specific format. And we have few requirements.

    • Add and remove items
    • Add content of myriad types to each item
    • Be able to reverse the item count (1 to 10 or 10 to 1)

    That’s really it. Except now I’m adding one more thing:

    • An easier, inline, way to add/remove/toggle items.

    So I sat and I thought about what would be the easiest to use, and I came up with a simple solution. Three buttons, one to add an item, one to remove, and one to toggle the order. Have those show perpetually at the bottom of the list, and you could easily add and remove as needed.

    It’s Actually Easy To Add Buttons

    Once I knew what I wanted, I took a page from some work Yoast is doing and sketched my idea to look like this:

    Three buttons: Add item, remove item, and toggle order

    In order to do this, I needed to add some code to the bottom of my <dl> code:

    <div className='listicles-buttons'>
    	<IconButton
    		icon='insert'
    		onClick={ () => setAttributes( { items: parseInt(`${ items }`)+1 } ) }
    		className='editor-inserter__toggle'
    	>Add Item</IconButton>
    
    	<IconButton
    		icon='dismiss'
    		onClick={ () => setAttributes( { items: parseInt(`${ items }`)-1 } ) }
    		className='editor-inserter__toggle'
    	>Remove Item</IconButton>
    
    	<IconButton
    		icon='controls-repeat'
    		onClick={ () => setAttributes( { reversed: ! reversed } ) }
    		className='editor-inserter__toggle'
    	>Toggle Order</IconButton>
    </div>

    This sits inside the <dl> and just below my <InnerBlocks...> insert. It generates the buttons, which change when you hover by default.

    Now it’s not perfect. If you deleted all the items and pressed delete again, it would sure try to delete. I didn’t put in checks to make sure we didn’t go below 0 or above 18 (which is my current limits). But this is the start to make sure we can keep improving and iterating.

  • Shortcodes Aren’t Leaving Us

    Shortcodes Aren’t Leaving Us

    In a recent post, someone asked:

    We have this scenario a lot:

    Lorem ipsum some text [shortcode]affected text[/shortcode] more text, all within one parapgraph.

    How can this be solved with Gutenberg?

    Quick answer? It won’t.

    Just like [shortcode] that outputs a single content, or [shortcode text="affected text"], there will remain a need for singe, inline, in context, shortcode for a while.

    I know it’s confusing. This is because there are different kinds of shortcodes for different purposes. Some, yes, will no longer be needed as much.

    Shortcodes for Inline Content

    This is the easiest one to understand. Think about videos. Or my example of inline editable blocks. Those are a very clear one to one. If you’re inserting a shortcode (or an embed) on it’s own line today, that will be ‘replaced’ in time with a block.

    Embeds are already supported, by the way. If you create your own embeds, they too are automatically blocked.

    Shortcodes for Layout

    This is harder to understand, since it’s not fully ready yet. But if you’ve used a plugin or a theme that told you to use a lot of shortcodes to make a two column layout, guess what you’re not going to be doing anymore in the future? That’s right, using shortcodes. Instead, we’re creating listicles, tables, how-to directions and more.

    Example of Yoast SEO’s How To Block — coming soon. (Credit: Yoast.com)

    Their looks a lot better than my basic blocks, but it shows you what we can do and how great we can do it. Those simple and complex layouts will become blocks, where we will be able to actually see what it’s supposed to look like. This includes the Gallery shortcode we all know and love.

    Shortcodes for Text Insertion

    And finally we have the ‘classic’ block. This is the sort the poster was asking me about. Guess what? Nothing’s going to change with those any time soon. Oh, I’m sure eventually someone will take my inline-editable-block concept and make it so when we add the shortcode, it’ll adjust the text accordingly right before our eyes.

    And really, if we look at the concept of [shortcode]affected text[/shortcode] we realize how much more we can do already with Gutenberg. What are we affecting the text with? We can already make it bold. But can we make it blue? Not yet. But I can see this coming soon.

    But right now? Those inline shortcodes, in the middle of your block, are staying put.

  • Context is Everything

    Context is Everything

    In the uptick of automated scans, we come to the place where we realize it’s not just the quality of content that matters in our success, but the context.

    Context in Content

    When you write content, the body of your work depends on the literary context of the words. Writing about technology on a non-tech site requires you to step back and explain the tech in a little more detail than you normally might. For example, if I were to post about shortcodes here, I would not bother to give you the history of what they were or why they’re used. I would trust you to know those things, or be ready and able to research them.

    By contrast, when writing about code used on a journalism site, and explaining we had a nifty new shortcode to do a thing, I absolutely would take time to explain. I would not expect my readers there, who care about the goings on of television, to understand about the weirdness of a shortcode. At the same time, I may not need to delve into details quite so much. I could just say “We have a new, faster way to add whatever, which will make it easier for us to report on X.”

    In short, I consider the audience when I write the content. I write contextually.

    Context in Code

    When it comes to writing code, there is a similar mindset. The code should make sense contextually and be consistent. If you’re using underscores for filenames, always use underscores, just to give one example. But this goes further than having a same prefix or formatting (tabs or spaces, eh?). It also means that when data is processed, it should be done so contextually.

    If you have a form, and you allow people to enter data to send to you, and that data is saved to a database, you have to sanitize the data. That’s a no-brainer for every developer worth the time of day. Never save unsanitized data, and sanitize as early as possible to minimize the possible damage. But deciding how best to sanitize can be tricky. PHP comes with stripslashes() for example, however consider that PHP says this:

    An example use of stripslashes() is when the PHP directive magic_quotes_gpc is on (it was on by default before PHP 5.4), and you aren’t inserting this data into a place (such as a database) that requires escaping. For example, if you’re simply outputting data straight from an HTML form.

    In other words, you shouldn’t use that to save data. Thankfully in WordPress (and Drupal and everything else) there are many ways to sanitize your inputted data based on … you guessed it, context. You don’t sanitize a URL as a plain text field, and you don’t sanitize an HTML form as a filename.

    When you write your code, sanitize, validate, and escape it contextually based on what it is.

    The Bottom Line: Context Matters

    This is the thing that automated checkers can’t quite do. They don’t know what the input is supposed to be unless you tell them, so they can’t verify your sanitization as well as a human can. Even grammar checkers can’t tell you when it’s okay to use slang and when it’s not, when you’re trying to explain a new concept.

    In the end? We need humans.

  • Show Feedback in “Right Now”

    Show Feedback in “Right Now”

    The “Right Now” section of the WordPress dashboard is a great way to get an overview of the goings on of your site. But it doesn’t quite list everything. What if you could add things like ‘messages’ to the the “At a Glance” section like this:

    The "At a Glance" section, with messages added in.

    Guess what? You can!

    The Code

    Presmuing you’re using Jetpack’s contact form module, you automatically get a new kind of post called ‘Feedback.’ In order to make it display it’s count in “At a Glance,” there are two parts. First we add the CSS, which does the styling. Then we add the PHP that counts and displays the number of posts in feedback.

    add_action( 'dashboard_glance_items', 'helf_dashboard_glance' );
    add_action( 'admin_head', 'helf_dashboard_glance_css' );
    
    /*
     * Show Feedback in "Right Now"
     */
    function helf_dashboard_glance() {
    	if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'contact-form' ) ) {
    		foreach ( array( 'feedback' ) as $post_type ) {
    			$num_posts   = wp_count_posts( $post_type );
    			$count_posts = ( isset( $num_posts->publish ) ) ? $num_posts->publish : '0';
    			if ( 0 !== $count_posts ) {
    				if ( 'feedback' === $post_type ) {
    					// translators: %s is the number of messages
    					$text = _n( '%s Message', '%s Messages', $count_posts );
    				}
    				$text = sprintf( $text, number_format_i18n( $count_posts ) );
    				printf( '<li class="%1$s-count"><a href="edit.php?post_type=%1$s">%2$s</a></li>', esc_attr( $post_type ), wp_kses_post( $text ) );
    			}
    		}
    	}
    }
    
    /*
     * Custom Icon for Feedback in "Right Now"
     */
    function helf_dashboard_glance_css() {
    	if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'contact-form' ) ) {
    		?>
    		<style type='text/css'>
    			#adminmenu #menu-posts-feedback div.wp-menu-image:before, #dashboard_right_now li.feedback-count a:before {
    				content: '\f466';
    				margin-left: -1px;
    			}
    		</style>
    		<?php
    	}
    }