Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: wordpress

  • The Passion of Change, Part 2

    The Passion of Change, Part 2

    This is part 2 of The Passion of Change. Last time I talked about some theory and decision to make about why to do this with WordPress. Now let’s talk about how it’s done.

    Collecting Data

    There’s no way around this. To collect data that’s … well … never been collected in one place before, you have to sit down and do the work. And it’s hard. This is why companies hire interns, but really you need a researcher who is an expert in the field. And you have to guess and what data is going to be important. Do you just want names and shows, or do you want death days, actors, and cliches and tropes? Decide on your datapoints, but collect more than you need. Trust me on that one. Backfilling dates for 1000 posts wasn’t fun.

    The trick with WordPress is understanding how to organize your data. With Hugo, there’s the basic concept of “everything is a post” and really that’s what WordPress does too. Everything is a post TYPE. By making a custom post type for your data, you can have it listed and organized how you want. We opted for a type for shows and characters, with post meta to store the complex and unique data and taxonomies for the common and shared.

    Display The Data

    Part of displaying your data properly is to do so in a way that is conducive to your SEO. Yeah I said a dirty word. CMB2 lets you add in post meta easily. Yoast SEO lets you add that information to your meta data. AMP makes it better to read on mobile, and FacetWP makes it dynamically sortable. And the Rest API? Well that makes it easily consumable. Anywhere.

    To make it easy to enter and maintain the data, we use CMB2. You can also use PODS or ACF to do this, and really it’s its own post. But the point here is you need to go back to that data you collected and figure out how it needs to be presented. While you could code it all by hand, I strongly recommend a plugin that will let you add in these fields more easily. You need to make sure you data can repeat what needs to be repeated.

    SEO

    And the best part here is that if you have good data and you’ve entered it in a smart way, it will lead to good SEO by doing things like this:

    %%title%% is a %%ct_lez_gender%% %%ct_lez_sexuality%% %cf_lezchars_type%% character played by %%actors%% on %%shows%% %%sep%% Clichés: %%ct_lez_cliches%%
    

    With Yoast SEO in conjunction with CMB2 I was able to auto-populate a unique and yet repeated description for my meta desc in all my posts. The goal here is to optimize smartly. You want your research to be found, so you need to make it easily finable for the right search queries.

    Mobile: AMP

    I use Automattic’s AMP plugin combined with Yoast’s AMP Glue plugin for mobile optimizations. By default it only adds posts as AMP data. I built out custom templates for my CPTs to allow those to show up as AMP pages as well. I did this because I wanted the data to be accessible in more ways than just normal WP pages. Democratizing consumability means being flexible about your displays. Get the data out there clearly.

    Don’t Predict Paths

    Putting the data out there in easy to find ways is step one. When you have lists of data, you also need to make them sortable. FacetWP is a tool for advanced filtering. It lets you sort and resort your data, so if you wanted a list of blue eyed, left handed, centipede groomers, and you had all that data stored, you could find it. It’s a little tricky sometimes to build out your facets the way you want, but they let you refine searches and drill down so you can find everything in the way the users want. The goal, and FacetWP meets it, is to make finding the data people want easier.

    But… There’s another path to consider. The REST API.

    This is hands down my favorite part of the whole thing. It’s great we have all this data we collected, and we can show it in myriad ways. We can get stats to show you trendlines and averages and percentages. But… How do we get the data back out there so other people can consume it? What if you wanted to take the data to make stats we didn’t? This is all done via the Rest API.

    JSON: It Gets The Job Done

    The Rest API made it EASY for me to export all this data into a format anyone could take and expand on. I made them simple, with just names and dates, and complex with everything I could think of. And by doing so, other people DID start to grab the data and use it to construct their own narratives and find their own answers.

    It also let me make a plugin!

    The irony of using a Rest API to power a plugin that lists dead female queers is not lost on me, by the way. I built out a JSON powered plugin that calls the data and uses it to output the data in widgets or shortcodes. It’s possibly the most simple and basic way you can do anything with this, but it demonstrates the extendability. It’s fast, it’s low load for my site which is always good, and it’s easy for me to update.

    All that work that went into the plugin, with the JSON API, was transformed into an Amazon Alexa skill, where you can ask it “Hey Alexa, ask Bury Your Queers who died on March 3rd” and your Echo or Dot will reply. At it’s heart, it seems silly and trivial. The more I worked on the code, though, the more I realized how you could extend this to share more data. Trivia and minutia are small beans, but they’re the beans we REMEMBER. And what we remember is what changes the world.

    Open Data – Sharing Passion Enhances Everything

    Hopefully the story you got from all this is that with WordPress you can share your passion for … well. Anything. And you can use it to fuel change. In the last 18 months, I’ve had the opportunity to talk to people world wide about how just seeing the representation and the statistics have helped them. Including TV producers. And yeah, that was weird. But more over, I’ve helped get data out there and used it to change one thing. And that is the passion that causes change.

  • The Passion of Change, Part 1

    The Passion of Change, Part 1

    One of WordPress’ big claims is that it democratizing publishing. In recent years, it’s also begun democratizing the distribution and consumption of data via the Rest API, and it’s helped push the openness of data, which can be used by anyone to make the world a little better.

    Change is born of many things but it always stems from a refusal to accept the norm. When Shay died on the TV show Chicago Fire, many of us were angry. When Lexa died on The 100, we became irate. And then we organized. Multiple groups, separate, all used WordPress and social media to power our desire to show the world what was wrong and what needed to change. We took our hobby of television and made it our passion, and we let our passion start to change the television landscape.

    WordPress Enables Change

    Having built many sites in many different CMS tools, ranging from Jekyll and Hugo to MediaWiki and Sharepoint, WordPress still makes it easiest to share the data in more ways than just plain old HTML. By allowing us to output our content in JSON with that API, we can create paths for people to transmute our data and display it in new ways we never dreamed of.

    In the last two years, I’ve been able to take my simply hobby site from a list of information to a open API for people to get lost in like Wikipedia to an open-data resource for all people to generate dynamic results. Without data we cannot come to accurate conclusions about the world, and without OPEN data, we cannot work together to make the world better.

    Taking a hobby as a vector for change didn’t happen overnight. It came with toil and hard work. It came with research of plugins and solutions. It came with hours and hours of watching TV just to come up with a reasonably accurate list of all the queer females on television, and if they were alive or dead. And with this data, we’ve been able to help news reporters and tv show writers visualize the impact on the world. We’ve started to change the world, just a little, with WordPress.

    Bury Your Queers

    Just telling people “Hey, WordPress helped me power a site that publicized the information of a hitherto uncollected dataset” would be a pretty short post.

    I mentioned change was born of a refusal to accept the ‘norm’ in our lives. As it happens, being a queer female on television is more dangerous than being on the Titanic. In 2014, it was reflecting the darkest aspects of ourselves. In 2015, 33 queer females died on TV. Over 40 in 2017. Trans people are being murdered in record numbers today in the real world. All of this is related to the Dead Lesbian trope, AKA Bury Your Queers.

    My theory is that the more we accept death in our media, the more we accept it in reality. The media is pervasive and colors our lenses to accept normal when it’s not. There are a lot of hills to stand on and make this point, but I picked the one that reflects me the most, and the one I felt I could tackle. My hope was that it would just be the start.

    A Brief History

    • December 13, 1971 – Julie Solkin / Executive Suite
    • August 15, 1995 – Talia Winters / Babylon 5
    • May 7, 2002 – Tara Maclay / Buffy The Vampire Slayer
    • May 13, 2014 – Leslie Shay / Chicago Fire
    • March 3, 2016 – Lexa / The 100
    • June 4, 2017 – Barbara Keen / Gotham

    It would take me a while to list all the deaths, so I’ve listed six of the more prominent deaths here. Julie was the first recorded death. Lexa set the world on fire. These deaths, out of well over 270 since 1971 by the way, shaped our perceptions. They told us it was okay to kill off the queers for shock value. But the thing is, with Lexa, last year, people lost their minds.

    If you were in the LA area, you may have seen some surprising billboards in 2016. There were four all told, four separate billboards crowdfunded globally via Tumblr, Twitter, Facebook, and a WordPress site. They collected the money and put the billboards up and said that WE would not stop. That wasn’t the end of it. There’s been a convention, ClexaCon, and more activism.

    Why WordPress?

    One of the interesting things was we all sat down, in our various corners of the internet, and asked “How bad is this, exactly?” Sites like AutoStraddle made a straight up (heh) list of all the dead and all the happy-endings. Spoiler, very few have happy endings. Other sites, like LGBT Fans Deserve Better and LezWatchTV started to make lists of everyone we could find. And we all actually used WordPress.

    There are pros and cons for every platform. There was never a doubt in Tracy’s mind that we were going to use WordPress, but I always think about pros and cons. MediaWiki is amazing when you want anyone contributing becuase it allows anonymous edits. But there was too much possibility for abuse so MediaWiki was out. Static site generators like Hugo or Jekyll are fast and secure (go on, hack my html please. Knock yourself OUT). But they’re not very flexible and can be difficult to manage with multiple contributors or non-technical ones. WordPress, though, is flexible, allows for multiple editors, processes images easily, and is incredibly extendable.

    What Next?

    Obviously I haven’t even begun to touch on the code part, of how you build out the data and make it beneficial to people via tools like plugins or Amazon Alexa, and not even how you build the data so you can do those things.

  • Hello Trello

    Hello Trello

    Organizing my life is usually done on the Apple Reminders app. I shove my to-dos in there and it alerts me when I forget about scheduled, repeated, events. Like mailing in a rent check.

    But when you have a group of people, it can be trickier, especially if you all use different devices and have different workflows.

    Enter Trello

    There are a lot of options out there, but Trello is free for the small scale. It’s easy to set up and my friend Tracy uses it a lot. When I realized we needed something better than my list to keep track of everything, I popped over to Trello to make it work.

    I’ve used it before, and I use Jira — which is owned by Trello’s Atlassian — so I’m familiar with the basic style of Kanban boards for tracking work. Every project has a ‘board’ and on the board you have ‘lists.’ In each list you have your ‘tasks’ which you drag from list to list to list. The general concept is you have a list of ‘backlog’ where you store everything. Tasks move from there to ‘in progress’ and then to ‘done’ (or they get archived).

    There are some things about the flow I find annoying. Like there isn’t a way to mark something as ‘done’ unless it’s scheduled, it just gets archived, but it can work. And you can integrate it with Slack so that’s nifty.

    What About WordPress?

    I’m going to shoot your hopes and dreams. There isn’t a WordPress plugin for Trello.

    Oh fine, there’s WP Trello but that actually is meant to display your boards as widgets or shortcodes. For the life of me, I can’t figure out why anyone would want to do that. No, what I mean is there’s no back-end WordPress plugin where I can go to, say, the dashboard and check out what boards and tasks are being worked on.

    I suppose that’s much the point, though. You shouldn’t be managing those things in WordPress. In fact, if you look into it, embedding Trello anywhere is kind of a mess. They clearly don’t want you to miss out on their API and their apps. Their experience matters.

    On the other hand they’re very hip on integration, letting people stick in one tool and access everything. I suspect the brunt of the lack of a WordPress tool is due to the fact that there’s no one recommended PHP API. If you go to their community page, you’ll see a lot of python and Ruby, but no PHP.

    What Can You Do With WordPress?

    Thankfully, you can integrate WordPress and Trello. There are extensions for Ninja Forms and Gravity Forms which let you integrate your form submissions and make them into Trello Tasks. If you use those plugins to allow visitors to post submissions, it’s a near perfect idea. They submit a post, you make a to-do, and your life remains organized instead of wondering who handled which submission.

    But if you’re looking for more, you need to consider a 3rd party integration via Zapier or IFTTT. There isn’t even a Jetpack contact form to Trello plugin.

    Yet.

  • Yes, You Can Use Enqueues

    Yes, You Can Use Enqueues

    One of the battles I face with plugins is explaining to people that they really do need to use wp_enqueue_scripts() for their code. And often I get an argument back that they can’t because they need to include parameters.

    Hold on to your hats. You totally can.

    The Misconception

    It’s easy to get confused with code. There are so many different ways to solve the same problem, we get twisted around. Let’s say that you wanted to include the following script in your website:

    <script src="https://mycoolsite.com/widget.js" async></script>
    

    That’s pretty straightforward in WordPress:

    wp_enqueue_script( 'my-widget', 'https://mycoolsite.com/widget.js', array( 'jquery' ), 1.0.0 );<
    

    But. What if you wanted to add this as well:

    <script type="text/javascript">
        var _widget_options = {
            theme: 'slow' // Choose from 'fast', 'stop', and 'slow'. Remove this property to get the default theme.
    };
    </script>
    

    Now you clearly have to hand-code this into WordPress. Right?

    Wrong!

    Use Inline Scripts!

    You may have heard about wp_add_inline_script before. If not, don’t feel bad. What this does is add extra, inline, code to an already enqueued script.

    Which means that to add the extra code, you do this:

    wp_add_inline_script( 'my-widget', 'var _widget_options = { theme: "slow" }', 'before' );
    

    Which will echo out exactly what you need.

    The cool thing about this, is what if you want your plugin to have a lot of options? Like you want to use the value for an option to determine what your script should do?

    $my-widget-inline = 'var _widget_options = { theme: "' . get_option( 'my-widget-theme' ) . '" }';
    wp_add_inline_script( 'my-widget', $my-widget-inline, 'before' );
    

    And now you’ve got flexibility.

    Keep In Mind…

    First, the name of the script matters. If you enqueue it as ‘my-widget’ then you call it as ‘my-widget’ as the first parameter in your inline script.

    Second, you can change ‘before’ to ‘after’ if you need it to be after the script.

    Third, as with all things, make sure you only load your javascript when you must. No one likes a slow site because you’re loading your javascript on every page when it only needs to be on a specific custom post type.

  • The Unbearable Uniqueness of Functions

    The Unbearable Uniqueness of Functions

    PHP 7.2 is on the horizon and one of the battles that we’re still facing is how to name our functions and classes. In WordPress, this is especially hard because we have to consider how our plugins and themes will be used in the global landscape.

    Everything Must Be Unique

    If you’ve written a self-contained PHP app, you know that you can’t give two functions the same name. So you have function enqueue_scripts and function enqueue_styles and function embed_content but you can’t declare them twice. Names must be unique within an app.

    When you consider the fact that all plugins and themes are third-party add-ons to WordPress, the naming situation gets messier. You can’t, for example, use function get_the_excerpt() because WordPress is using it. So you have to introduce prefixes to your plugin (let’s call it “Caffeinated”) like this: function caff_get_the_excerpt()

    That works well until someone creates an add-on to your plugin, call it “Decaffeinated”, and they need to use function decaff_get_the_excerpt() which isn’t so bad, but “Tea Caffeinated” has to either use a prefix of tea_caff_ or caff_tea_ and the more you travel down the road, the messier it gets.

    Prevent Collisions

    The whole point of this exercise in naming is, you see, to prevent collisions between your code and the parent projects you’re working with. You can’t use __ as a function prefix, for example, because that’s magical in PHP land. You can’t use wp_ or wordpress_ in WordPress, because … well. You’re not WordPress.

    But preventing collisions gets long and messy and convoluted and you end up with prefixes like edd_stbe_ which is unique but can be difficult to remember what it’s for. That’s why, thankfully, we have the option of a little more selective naming.

    Selective Uniqueness

    Back in PHP 5, the object model was rewritten to allow for better performance and more features. And this allows us to make Classes which contain our functions, named whatever we want:

    class Caffeinated {
        function get_the_excerpt() { ... }
    }
    new Caffeinated();
    

    This is extended to the add-on plugins, So we could have class Decaffeinated and class Caffeinated_Tea but within the classes, our functions are more simply named. Also we can call functions from one class into another, like Tea could call Caffeinated::get_the_excerpt() and easily filter that function.

    Why is this good? Well it lets you keep the function names simple, but the class name distinctive and thus easier to remember.

    Simple Names are Better

    One of the cardinal rules about domain names is that shorter is better. The same goes for functions and classes, to a degree. As Otto likes to say, a well named function doesn’t really need documentation. And one of the ways you can get a well named function is by putting it in a well named class. You can also use Namespaces.

    Namespaces are magical. By adding namespace Caffeinated; to your plugin file, for example, you can then have a classname of class Settings and not have to worry about collisions, because your class name is prefixed automatically by the namespace. This extends to functions, as you can us function admin for admin settings in the Settings class, in the Caffeinated namespace. And to call that? Use Caffeinated\Settings::admin();

    There’s a lot more you can do with Namespaces, of course, but using them to stop your code from crashing into other people’s, while still keeping names obvious, unique, and memorable? Well they’re pretty nifty.

    Remember: What’s Your Global?

    At the end of the day, the big thing to remember is what your globals are.

    • Outside of a class or namespace, a function is a global.
    • Outside of a namespace, a class is a global.
    • Outside of a namespace, a namespace is global.

    Yes, you can have sub-namespaces. But the point is that top-level whatever you pick, be it a function, class, or namespace, must be named uniquely and distinctly and, in my opinion, relative to the code it’s in. Naming things generically ends in tears as they’ll probably conflict.

  • FacetWP, JSON API, and WP_Query Searches

    FacetWP, JSON API, and WP_Query Searches

    One of the ways that FacetWP works is that it adds <!--fwp-loop--> to the source of your outputted page when it detects you used a search query and it can’t find it’s usual classes. This is so that it’s various features like refreshes and so on. It’s a good thing.

    At least it is until you’re trying to use a WP_Query based search to find titles “like” something, and you find your JSON output prefixed…

    Mostly Harmless

    Most of the time when you see <!--fwp-loop--> in the source code, you don’t care. It doesn’t impact anything and it helps Facet work. This is especially important when you have a ‘weird’ theme or plugins that mess with output.

    The issue is that this is how Facet decides if you need that output:

    $is_main_query = ( $query->is_archive || $query->is_search || ( $query->is_main_query() && ! $query->is_singular ) );
    

    Most of the time, that makes perfect sense. It just happens that I’m calling search in a place where that output is a bad idea. Like this:

    {“id”:6294,”name”:”Alex”,”shows”:”Witches of East End”,”url”:”https:\/\/tv.lezpress.dev\/character\/alex\/”,”died”:”alive”}

    Whoops.

    Annoying, But Not Impossible, To Fix

    After bashing my head in for a while, I grep’d the code for Facet, found where it was being set, and then read the help document on facetwp_is_main_query which told me that I could filter the function.

    In this case, I needed to set the value to false to get it to stop outputting, so I used this:

    add_filter( 'facetwp_is_main_query', function( $is_main_query, $query ) { return false; }, 10, 2 );
    

    Be careful where you put that by the way. If you put it on all pages, you’ll break your Facets. I put it in the function that generates the JSON output which limits it heavily, just as I want it to.